fix: restore settings sidebar, rename labels, fix SonarQube issues, and extract user-actions page

- Restore settings sidebar in MainNavigation (lost during epic/v5 merge)
- Rename "Configuration" to "Settings", "Look & Feel" to "Appearance", etc.
- Fix SonarQube issues: duplicate class, regex injection, nested ternary, inline arrow functions
- Extract User Actions from Connect Your App into its own settings page
- Update all i18n translation keys across locales

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dhruwang
2026-04-30 15:41:50 +05:30
parent 7d1c02b54b
commit 1ecc9f1722
31 changed files with 669 additions and 533 deletions
@@ -32,6 +32,7 @@ import {
getWorkspacesForSwitcherAction,
} from "@/app/(app)/workspaces/[workspaceId]/actions";
import { NavigationLink } from "@/app/(app)/workspaces/[workspaceId]/components/NavigationLink";
import { SettingsSidebarContent } from "@/app/(app)/workspaces/[workspaceId]/components/SettingsSidebarContent";
import { isNewerVersion } from "@/app/(app)/workspaces/[workspaceId]/lib/utils";
import FBLogo from "@/images/formbricks-wordmark.svg";
import { cn } from "@/lib/cn";
@@ -52,6 +53,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/modules/ui/components/dropdown-menu";
import { GoBackButton } from "@/modules/ui/components/go-back-button";
import { ModalButton } from "@/modules/ui/components/upgrade-prompt";
import { CreateWorkspaceModal } from "@/modules/workspaces/components/create-workspace-modal";
import { WorkspaceLimitModal } from "@/modules/workspaces/components/workspace-limit-modal";
@@ -73,22 +75,24 @@ interface NavigationProps {
}
const isActiveWorkspaceSetting = (pathname: string, settingId: string): boolean => {
if (pathname.includes("/settings/")) {
return false;
}
const pattern = new RegExp(`/workspace/${settingId}(?:/|$)`);
return pattern.test(pathname);
const segment = `/settings/workspace/${settingId}`;
return pathname.includes(segment + "/") || pathname.endsWith(segment);
};
const isActiveOrganizationSetting = (pathname: string, settingId: string): boolean => {
const accountSettingsPattern = /\/settings\/(profile|account|notifications|security|appearance)(?:\/|$)/;
if (accountSettingsPattern.test(pathname)) {
const accountPrefixes = [
"/settings/profile",
"/settings/account",
"/settings/notifications",
"/settings/security",
"/settings/appearance",
];
if (accountPrefixes.some((prefix) => pathname.includes(prefix + "/") || pathname.endsWith(prefix))) {
return false;
}
const pattern = new RegExp(`/settings/${settingId}(?:/|$)`);
return pattern.test(pathname);
const segment = `/settings/${settingId}`;
return pathname.includes(segment + "/") || pathname.endsWith(segment);
};
export const MainNavigation = ({
@@ -120,6 +124,7 @@ export const MainNavigation = ({
: t("common.you_are_not_authorized_to_perform_this_action");
const isOwnerOrManager = isManager || isOwner;
const isSettingsMode = pathname?.includes("/settings");
const toggleSidebar = () => {
setIsCollapsed(!isCollapsed);
@@ -139,13 +144,6 @@ export const MainNavigation = ({
return () => clearTimeout(timeoutId);
}, [isCollapsed]);
useEffect(() => {
// Auto collapse workspace navbar on org and account settings
if (pathname?.includes("/settings")) {
setIsCollapsed(true);
}
}, [pathname]);
const mainNavigationSections = useMemo(
() => [
{
@@ -198,29 +196,21 @@ export const MainNavigation = ({
[t, workspace.id, pathname, isMembershipPending, isBilling]
);
const configurationNavigationItem = useMemo(
const settingsNavigationItem = useMemo(
() => ({
name: t("common.configuration"),
href: `/workspaces/${workspace.id}/general`,
icon: Cog,
isActive:
pathname?.includes("/general") ||
pathname?.includes("/look") ||
pathname?.includes("/app-connection") ||
pathname?.includes("/feedback-sources") ||
pathname?.includes("/integrations") ||
pathname?.includes("/teams") ||
pathname?.includes("/languages") ||
pathname?.includes("/tags"),
name: t("common.settings"),
href: `/workspaces/${workspace.id}/settings`,
icon: SettingsIcon,
isActive: isSettingsMode,
disabled: isMembershipPending || isBilling,
}),
[t, workspace.id, pathname, isMembershipPending, isBilling]
[t, workspace.id, isSettingsMode, isMembershipPending, isBilling]
);
const dropdownNavigation = [
{
label: t("common.account"),
href: `/workspaces/${workspace.id}/settings/profile`,
href: `/workspaces/${workspace.id}/settings/account/profile`,
icon: UserCircleIcon,
},
{
@@ -263,17 +253,17 @@ export const MainNavigation = ({
{
id: "general",
label: t("common.general"),
href: `/workspaces/${workspace.id}/general`,
href: `/workspaces/${workspace.id}/settings/workspace/general`,
},
{
id: "look",
label: t("common.look_and_feel"),
href: `/workspaces/${workspace.id}/look`,
label: t("common.appearance"),
href: `/workspaces/${workspace.id}/settings/workspace/look`,
},
{
id: "app-connection",
label: t("common.website_and_app_connection"),
href: `/workspaces/${workspace.id}/app-connection`,
label: t("common.connect_your_app"),
href: `/workspaces/${workspace.id}/settings/workspace/app-connection`,
},
{
id: "feedback-sources",
@@ -283,22 +273,22 @@ export const MainNavigation = ({
{
id: "integrations",
label: t("common.integrations"),
href: `/workspaces/${workspace.id}/integrations`,
href: `/workspaces/${workspace.id}/settings/workspace/integrations`,
},
{
id: "teams",
label: t("common.team_access"),
href: `/workspaces/${workspace.id}/teams`,
href: `/workspaces/${workspace.id}/settings/workspace/teams`,
},
{
id: "languages",
label: t("common.survey_languages"),
href: `/workspaces/${workspace.id}/languages`,
href: `/workspaces/${workspace.id}/settings/workspace/languages`,
},
{
id: "tags",
label: t("common.tags"),
href: `/workspaces/${workspace.id}/tags`,
href: `/workspaces/${workspace.id}/settings/workspace/tags`,
},
];
@@ -310,7 +300,7 @@ export const MainNavigation = ({
},
{
id: "teams",
label: t("common.members_and_teams"),
label: t("common.teams"),
href: `/workspaces/${workspace.id}/settings/teams`,
},
{
@@ -528,6 +518,28 @@ export const MainNavigation = ({
];
};
const handleSettingsWorkspaceChange = useCallback(
(id: string) => {
startTransition(() => {
router.push(`/workspaces/${id}/settings/workspace/general`);
});
},
[router]
);
const handleSettingsOrganizationChange = useCallback(
(id: string) => {
startTransition(() => {
if (id === organization.id) {
router.push(`/workspaces/${workspace.id}/settings/organization/general`);
} else {
router.push(`/organizations/${id}/`);
}
});
},
[router, organization.id, workspace.id]
);
const switcherTriggerClasses = cn(
"w-full border-t px-3 py-3 text-left transition-colors duration-200 hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-500 focus-visible:ring-inset",
isCollapsed ? "flex items-center justify-center" : ""
@@ -544,353 +556,386 @@ export const MainNavigation = ({
<aside
className={cn(
"z-40 flex flex-col justify-between rounded-r-xl border-r border-slate-200 bg-white pt-3 shadow-md transition-all duration-100",
isCollapsed ? "w-sidebar-expanded" : "w-sidebar-collapsed"
isSettingsMode || !isCollapsed ? "w-sidebar-collapsed" : "w-sidebar-expanded"
)}>
<div>
{/* Logo and Toggle */}
{isSettingsMode ? (
<div className="flex flex-col overflow-hidden">
<div className="mb-2 px-3">
<GoBackButton url={`/workspaces/${workspace.id}/surveys`} />
</div>
<div className="flex items-center justify-between px-3 pb-4">
{!isCollapsed && (
<Link
href={mainNavigationLink}
className={cn(
"flex items-center justify-center transition-opacity duration-100",
isTextVisible ? "opacity-0" : "opacity-100"
)}>
<Image src={FBLogo} width={160} height={30} alt={t("workspace.formbricks_logo")} />
</Link>
)}
<Button
variant="ghost"
size="icon"
onClick={toggleSidebar}
className={cn(
"rounded-xl bg-slate-50 p-1 text-slate-600 transition-all hover:bg-slate-100 focus:outline-none focus:ring-0 focus:ring-transparent"
)}>
{isCollapsed ? (
<PanelLeftOpenIcon strokeWidth={1.5} />
) : (
<PanelLeftCloseIcon strokeWidth={1.5} />
)}
</Button>
{/* Settings sidebar content */}
<SettingsSidebarContent
workspaceId={workspace.id}
workspaceName={workspace.name}
organizationId={organization.id}
organizationName={organization.name}
membershipRole={membershipRole}
isFormbricksCloud={isFormbricksCloud}
isCollapsed={false}
isTextVisible={false}
workspaces={workspaces}
isLoadingWorkspaces={isLoadingWorkspaces}
onWorkspaceChange={handleSettingsWorkspaceChange}
onWorkspaceDropdownOpen={loadWorkspaces}
organizations={organizations}
isLoadingOrganizations={isLoadingOrganizations}
onOrganizationChange={handleSettingsOrganizationChange}
onOrganizationDropdownOpen={loadOrganizations}
/>
</div>
) : (
<div>
{/* Logo and Toggle */}
{/* Main Nav Switch */}
<ul className="space-y-2">
{mainNavigationSections.map((section) => (
<li key={section.id}>
{!isCollapsed && !isTextVisible && (
<p className="px-4 pb-1 pt-2 text-xs font-semibold uppercase tracking-wide text-slate-400">
{section.name}
</p>
<div className="flex items-center justify-between px-3 pb-4">
{!isCollapsed && (
<Link
href={mainNavigationLink}
className={cn(
"flex items-center justify-center transition-opacity duration-100",
isTextVisible ? "opacity-0" : "opacity-100"
)}>
<Image src={FBLogo} width={160} height={30} alt={t("workspace.formbricks_logo")} />
</Link>
)}
<Button
variant="ghost"
size="icon"
onClick={toggleSidebar}
className={cn(
"rounded-xl bg-slate-50 p-1 text-slate-600 transition-all hover:bg-slate-100 focus:outline-none focus:ring-0 focus:ring-transparent"
)}>
{isCollapsed ? (
<PanelLeftOpenIcon strokeWidth={1.5} />
) : (
<PanelLeftCloseIcon strokeWidth={1.5} />
)}
</Button>
</div>
<ul>
{section.items.map(
(item) =>
!item.isHidden && (
<NavigationLink
key={item.name}
href={item.href}
isActive={item.isActive}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
disabled={item.disabled}
disabledMessage={item.disabled ? disabledNavigationMessage : undefined}
linkText={item.name}>
<item.icon strokeWidth={1.5} />
</NavigationLink>
)
{/* Main Nav */}
<ul className="space-y-2">
{mainNavigationSections.map((section) => (
<li key={section.id}>
{!isCollapsed && !isTextVisible && (
<p className="px-4 pb-1 pt-2 text-xs font-semibold uppercase tracking-wide text-slate-400">
{section.name}
</p>
)}
<ul>
{section.items.map(
(item) =>
!item.isHidden && (
<NavigationLink
key={item.name}
href={item.href}
isActive={item.isActive}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
disabled={item.disabled}
disabledMessage={item.disabled ? disabledNavigationMessage : undefined}
linkText={item.name}>
<item.icon strokeWidth={1.5} />
</NavigationLink>
)
)}
</ul>
</li>
))}
<li className={cn("mt-2 border-t border-slate-100 pt-2", isCollapsed && "border-t-0 pt-0")}>
<ul>
<NavigationLink
href={settingsNavigationItem.href}
isActive={settingsNavigationItem.isActive}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
disabled={settingsNavigationItem.disabled}
disabledMessage={
settingsNavigationItem.disabled ? disabledNavigationMessage : undefined
}
linkText={settingsNavigationItem.name}>
<settingsNavigationItem.icon strokeWidth={1.5} />
</NavigationLink>
</ul>
</li>
))}
</ul>
</div>
)}
<li className={cn("mt-2 border-t border-slate-100 pt-2", isCollapsed && "border-t-0 pt-0")}>
<ul>
<NavigationLink
href={configurationNavigationItem.href}
isActive={configurationNavigationItem.isActive}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
disabled={configurationNavigationItem.disabled}
disabledMessage={
configurationNavigationItem.disabled ? disabledNavigationMessage : undefined
}
linkText={configurationNavigationItem.name}>
<configurationNavigationItem.icon strokeWidth={1.5} />
</NavigationLink>
</ul>
</li>
</ul>
</div>
{!isSettingsMode && (
<div>
{/* New Version Available */}
{!isCollapsed && isOwnerOrManager && latestVersion && !isFormbricksCloud && !isDevelopment && (
<Link
href="https://github.com/formbricks/formbricks/releases"
target="_blank"
className="m-2 flex items-center space-x-4 rounded-lg border border-slate-200 bg-slate-100 p-2 text-sm text-slate-800 hover:border-slate-300 hover:bg-slate-200">
<p className="flex items-center justify-center gap-x-2 text-xs">
<RocketIcon strokeWidth={1.5} className="mx-1 h-6 w-6 text-slate-900" />
{t("common.new_version_available", { version: latestVersion })}
</p>
</Link>
)}
<div>
{/* New Version Available */}
{!isCollapsed && isOwnerOrManager && latestVersion && !isFormbricksCloud && !isDevelopment && (
<Link
href="https://github.com/formbricks/formbricks/releases"
target="_blank"
className="m-2 flex items-center space-x-4 rounded-lg border border-slate-200 bg-slate-100 p-2 text-sm text-slate-800 hover:border-slate-300 hover:bg-slate-200">
<p className="flex items-center justify-center gap-x-2 text-xs">
<RocketIcon strokeWidth={1.5} className="mx-1 h-6 w-6 text-slate-900" />
{t("common.new_version_available", { version: latestVersion })}
</p>
</Link>
)}
{/* Trial Days Remaining */}
{!isCollapsed && isFormbricksCloud && trialDaysRemaining !== null && (
<Link href={`/workspaces/${workspace.id}/settings/billing`} className="m-2 block">
<TrialAlert trialDaysRemaining={trialDaysRemaining} size="small" />
</Link>
)}
{/* Trial Days Remaining */}
{!isCollapsed && isFormbricksCloud && trialDaysRemaining !== null && (
<Link href={`/workspaces/${workspace.id}/settings/billing`} className="m-2 block">
<TrialAlert trialDaysRemaining={trialDaysRemaining} size="small" />
</Link>
)}
<div className="flex flex-col">
<DropdownMenu onOpenChange={setIsWorkspaceDropdownOpen}>
<DropdownMenuTrigger asChild id="workspaceDropdownTrigger" className={switcherTriggerClasses}>
<button
type="button"
aria-label={isCollapsed ? t("common.change_workspace") : undefined}
className={cn("flex w-full items-center gap-3", isCollapsed && "justify-center")}>
<span className={switcherIconClasses}>
<FoldersIcon className="h-4 w-4" strokeWidth={1.5} />
</span>
{!isCollapsed && !isTextVisible && (
<div className="flex flex-col">
<DropdownMenu onOpenChange={setIsWorkspaceDropdownOpen}>
<DropdownMenuTrigger
asChild
id="workspaceDropdownTrigger"
className={switcherTriggerClasses}>
<button
type="button"
aria-label={isCollapsed ? t("common.change_workspace") : undefined}
className={cn("flex w-full items-center gap-3", isCollapsed && "justify-center")}>
<span className={switcherIconClasses}>
<FoldersIcon className="h-4 w-4" strokeWidth={1.5} />
</span>
{!isCollapsed && !isTextVisible && (
<>
<div className="grow overflow-hidden">
<p className="truncate text-sm font-bold text-slate-700">{workspace.name}</p>
<p className="text-sm text-slate-500">{t("common.workspace")}</p>
</div>
{isPending && (
<Loader2 className="h-4 w-4 animate-spin text-slate-600" strokeWidth={1.5} />
)}
<ChevronRightIcon className="h-4 w-4 shrink-0 text-slate-600" strokeWidth={1.5} />
</>
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" sideOffset={10} alignOffset={5} align="end">
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<FoldersIcon className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.change_workspace")}
</div>
{(isLoadingWorkspaces || isInitialWorkspacesLoading) && (
<div className="flex items-center justify-center py-2">
<Loader2 className="h-4 w-4 animate-spin" />
</div>
)}
{!isLoadingWorkspaces &&
!isInitialWorkspacesLoading &&
workspaceLoadError &&
renderSwitcherError(
workspaceLoadError,
() => {
setWorkspaceLoadError(null);
setWorkspaces([]);
},
t("common.try_again")
)}
{!isLoadingWorkspaces && !isInitialWorkspacesLoading && !workspaceLoadError && (
<>
<div className="grow overflow-hidden">
<p className="truncate text-sm font-bold text-slate-700">{workspace.name}</p>
<p className="text-sm text-slate-500">{t("common.workspace")}</p>
</div>
{isPending && (
<Loader2 className="h-4 w-4 animate-spin text-slate-600" strokeWidth={1.5} />
<DropdownMenuGroup className="max-h-[300px] overflow-y-auto">
{workspaces.map((proj) => (
<DropdownMenuCheckboxItem
key={proj.id}
checked={proj.id === workspace.id}
onClick={() => handleWorkspaceChange(proj.id)}
className="cursor-pointer">
{proj.name}
</DropdownMenuCheckboxItem>
))}
</DropdownMenuGroup>
{isOwnerOrManager && (
<DropdownMenuCheckboxItem
onClick={handleWorkspaceCreate}
className="w-full cursor-pointer justify-between">
<span>{t("common.add_new_workspace")}</span>
<PlusIcon className="ml-2 h-4 w-4" strokeWidth={1.5} />
</DropdownMenuCheckboxItem>
)}
<ChevronRightIcon className="h-4 w-4 shrink-0 text-slate-600" strokeWidth={1.5} />
</>
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" sideOffset={10} alignOffset={5} align="end">
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<FoldersIcon className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.change_workspace")}
</div>
{(isLoadingWorkspaces || isInitialWorkspacesLoading) && (
<div className="flex items-center justify-center py-2">
<Loader2 className="h-4 w-4 animate-spin" />
</div>
)}
{!isLoadingWorkspaces &&
!isInitialWorkspacesLoading &&
workspaceLoadError &&
renderSwitcherError(
workspaceLoadError,
() => {
setWorkspaceLoadError(null);
setWorkspaces([]);
},
t("common.try_again")
)}
{!isLoadingWorkspaces && !isInitialWorkspacesLoading && !workspaceLoadError && (
<>
<DropdownMenuGroup className="max-h-[300px] overflow-y-auto">
{workspaces.map((proj) => (
<DropdownMenuCheckboxItem
key={proj.id}
checked={proj.id === workspace.id}
onClick={() => handleWorkspaceChange(proj.id)}
className="cursor-pointer">
{proj.name}
</DropdownMenuCheckboxItem>
))}
</DropdownMenuGroup>
{isOwnerOrManager && (
<DropdownMenuCheckboxItem
onClick={handleWorkspaceCreate}
className="w-full cursor-pointer justify-between">
<span>{t("common.add_new_workspace")}</span>
<PlusIcon className="ml-2 h-4 w-4" strokeWidth={1.5} />
</DropdownMenuCheckboxItem>
)}
</>
)}
<DropdownMenuSeparator />
<DropdownMenuGroup>
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<Cog className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.workspace_configuration")}
</div>
{workspaceSettings.map((setting) => (
<DropdownMenuCheckboxItem
key={setting.id}
checked={isActiveWorkspaceSetting(pathname, setting.id)}
onClick={() => handleSettingNavigation(setting.href)}
className="cursor-pointer">
{setting.label}
</DropdownMenuCheckboxItem>
))}
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu onOpenChange={setIsOrganizationDropdownOpen}>
<DropdownMenuTrigger
asChild
id="organizationDropdownTriggerSidebar"
className={switcherTriggerClasses}>
<button
type="button"
aria-label={isCollapsed ? t("common.change_organization") : undefined}
className={cn("flex w-full items-center gap-3", isCollapsed && "justify-center")}>
<span className={switcherIconClasses}>
<Building2Icon className="h-4 w-4" strokeWidth={1.5} />
</span>
{!isCollapsed && !isTextVisible && (
<>
<div className="grow overflow-hidden">
<p className="truncate text-sm font-bold text-slate-700">{organization.name}</p>
<p className="text-sm text-slate-500">{t("common.organization")}</p>
</div>
{isPending && (
<Loader2 className="h-4 w-4 animate-spin text-slate-600" strokeWidth={1.5} />
)}
<ChevronRightIcon className="h-4 w-4 shrink-0 text-slate-600" strokeWidth={1.5} />
</>
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" sideOffset={10} alignOffset={5} align="end">
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<Building2Icon className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.change_organization")}
</div>
{isLoadingOrganizations && (
<div className="flex items-center justify-center py-2">
<Loader2 className="h-4 w-4 animate-spin" />
</div>
)}
{!isLoadingOrganizations &&
organizationLoadError &&
renderSwitcherError(
organizationLoadError,
() => {
setOrganizationLoadError(null);
setOrganizations([]);
},
t("common.try_again")
)}
{!isLoadingOrganizations && !organizationLoadError && (
<>
<DropdownMenuGroup className="max-h-[300px] overflow-y-auto">
{organizations.map((org) => (
<DropdownMenuCheckboxItem
key={org.id}
checked={org.id === organization.id}
onClick={() => handleOrganizationChange(org.id)}
className="cursor-pointer">
{org.name}
</DropdownMenuCheckboxItem>
))}
</DropdownMenuGroup>
{isMultiOrgEnabled && (
<DropdownMenuCheckboxItem
onClick={() => setOpenCreateOrganizationModal(true)}
className="w-full cursor-pointer justify-between">
<span>{t("common.create_new_organization")}</span>
<PlusIcon className="ml-2 h-4 w-4" strokeWidth={1.5} />
</DropdownMenuCheckboxItem>
)}
</>
)}
<DropdownMenuSeparator />
<DropdownMenuGroup>
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<SettingsIcon className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.organization_settings")}
</div>
{organizationSettings.map((setting) => {
if (setting.hidden) return null;
return (
<DropdownMenuSeparator />
<DropdownMenuGroup>
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<Cog className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.workspace_configuration")}
</div>
{workspaceSettings.map((setting) => (
<DropdownMenuCheckboxItem
key={setting.id}
checked={isActiveOrganizationSetting(pathname, setting.id)}
checked={isActiveWorkspaceSetting(pathname, setting.id)}
onClick={() => handleSettingNavigation(setting.href)}
className="cursor-pointer">
{setting.label}
</DropdownMenuCheckboxItem>
);
})}
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
))}
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
<DropdownMenuTrigger
asChild
id="userDropdownTrigger"
className={cn(switcherTriggerClasses, "rounded-br-xl")}>
<button
type="button"
aria-label={isCollapsed ? t("common.account_settings") : undefined}
className={cn("flex w-full items-center gap-3", isCollapsed && "justify-center")}>
<span className={switcherIconClasses}>
<ProfileAvatar userId={user.id} />
</span>
{!isCollapsed && !isTextVisible && (
<DropdownMenu onOpenChange={setIsOrganizationDropdownOpen}>
<DropdownMenuTrigger
asChild
id="organizationDropdownTriggerSidebar"
className={switcherTriggerClasses}>
<button
type="button"
aria-label={isCollapsed ? t("common.change_organization") : undefined}
className={cn("flex w-full items-center gap-3", isCollapsed && "justify-center")}>
<span className={switcherIconClasses}>
<Building2Icon className="h-4 w-4" strokeWidth={1.5} />
</span>
{!isCollapsed && !isTextVisible && (
<>
<div className="grow overflow-hidden">
<p className="truncate text-sm font-bold text-slate-700">{organization.name}</p>
<p className="text-sm text-slate-500">{t("common.organization")}</p>
</div>
{isPending && (
<Loader2 className="h-4 w-4 animate-spin text-slate-600" strokeWidth={1.5} />
)}
<ChevronRightIcon className="h-4 w-4 shrink-0 text-slate-600" strokeWidth={1.5} />
</>
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" sideOffset={10} alignOffset={5} align="end">
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<Building2Icon className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.change_organization")}
</div>
{isLoadingOrganizations && (
<div className="flex items-center justify-center py-2">
<Loader2 className="h-4 w-4 animate-spin" />
</div>
)}
{!isLoadingOrganizations &&
organizationLoadError &&
renderSwitcherError(
organizationLoadError,
() => {
setOrganizationLoadError(null);
setOrganizations([]);
},
t("common.try_again")
)}
{!isLoadingOrganizations && !organizationLoadError && (
<>
<div className="grow overflow-hidden">
<p
title={user?.email}
className="ph-no-capture ph-no-capture -mb-0.5 truncate text-sm font-bold text-slate-700">
{user?.name ? <span>{user?.name}</span> : <span>{user?.email}</span>}
</p>
<p className="text-sm text-slate-500">{t("common.account")}</p>
</div>
<ChevronRightIcon className="h-4 w-4 shrink-0 text-slate-600" strokeWidth={1.5} />
<DropdownMenuGroup className="max-h-[300px] overflow-y-auto">
{organizations.map((org) => (
<DropdownMenuCheckboxItem
key={org.id}
checked={org.id === organization.id}
onClick={() => handleOrganizationChange(org.id)}
className="cursor-pointer">
{org.name}
</DropdownMenuCheckboxItem>
))}
</DropdownMenuGroup>
{isMultiOrgEnabled && (
<DropdownMenuCheckboxItem
onClick={() => setOpenCreateOrganizationModal(true)}
className="w-full cursor-pointer justify-between">
<span>{t("common.create_new_organization")}</span>
<PlusIcon className="ml-2 h-4 w-4" strokeWidth={1.5} />
</DropdownMenuCheckboxItem>
)}
</>
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<div className="px-2 py-1.5 text-sm font-medium text-slate-500">
<SettingsIcon className="mr-2 inline h-4 w-4" strokeWidth={1.5} />
{t("common.organization_settings")}
</div>
{organizationSettings.map((setting) => {
if (setting.hidden) return null;
return (
<DropdownMenuCheckboxItem
key={setting.id}
checked={isActiveOrganizationSetting(pathname, setting.id)}
onClick={() => handleSettingNavigation(setting.href)}
className="cursor-pointer">
{setting.label}
</DropdownMenuCheckboxItem>
);
})}
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenuContent
id="userDropdownInnerContentWrapper"
side="right"
sideOffset={10}
alignOffset={5}
align="end">
{dropdownNavigation.map((link) => (
<Link
href={link.href}
target={link.target}
className="flex w-full items-center"
key={link.label}
rel={link.target === "_blank" ? "noopener noreferrer" : undefined}>
<DropdownMenuItem>
<link.icon className="mr-2 h-4 w-4" strokeWidth={1.5} />
{link.label}
</DropdownMenuItem>
</Link>
))}
<DropdownMenuItem
onClick={async () => {
const loginUrl = `${publicDomain}/auth/login`;
const route = await signOutWithAudit({
reason: "user_initiated",
redirectUrl: loginUrl,
organizationId: organization.id,
redirect: false,
callbackUrl: loginUrl,
clearWorkspaceId: true,
});
router.push(route?.url || loginUrl); // NOSONAR // We want to check for empty strings
}}
icon={<LogOutIcon className="mr-2 h-4 w-4" strokeWidth={1.5} />}>
{t("common.logout")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<DropdownMenu>
<DropdownMenuTrigger
asChild
id="userDropdownTrigger"
className={cn(switcherTriggerClasses, "rounded-br-xl")}>
<button
type="button"
aria-label={isCollapsed ? t("common.account_settings") : undefined}
className={cn("flex w-full items-center gap-3", isCollapsed && "justify-center")}>
<span className={switcherIconClasses}>
<ProfileAvatar userId={user.id} />
</span>
{!isCollapsed && !isTextVisible && (
<>
<div className="grow overflow-hidden">
<p
title={user?.email}
className="ph-no-capture -mb-0.5 truncate text-sm font-bold text-slate-700">
{user?.name ? <span>{user?.name}</span> : <span>{user?.email}</span>}
</p>
<p className="text-sm text-slate-500">{t("common.account")}</p>
</div>
<ChevronRightIcon className="h-4 w-4 shrink-0 text-slate-600" strokeWidth={1.5} />
</>
)}
</button>
</DropdownMenuTrigger>
<DropdownMenuContent
id="userDropdownInnerContentWrapper"
side="right"
sideOffset={10}
alignOffset={5}
align="end">
{dropdownNavigation.map((link) => (
<Link
href={link.href}
target={link.target}
className="flex w-full items-center"
key={link.label}
rel={link.target === "_blank" ? "noopener noreferrer" : undefined}>
<DropdownMenuItem>
<link.icon className="mr-2 h-4 w-4" strokeWidth={1.5} />
{link.label}
</DropdownMenuItem>
</Link>
))}
<DropdownMenuItem
onClick={async () => {
const loginUrl = `${publicDomain}/auth/login`;
const route = await signOutWithAudit({
reason: "user_initiated",
redirectUrl: loginUrl,
organizationId: organization.id,
redirect: false,
callbackUrl: loginUrl,
clearWorkspaceId: true,
});
router.push(route?.url || loginUrl);
}}
icon={<LogOutIcon className="mr-2 h-4 w-4" strokeWidth={1.5} />}>
{t("common.logout")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
</div>
)}
</aside>
)}
{openWorkspaceLimitModal && (
@@ -255,15 +255,22 @@ export const SettingsSidebarContent = ({
disabled: isBilling,
},
{
id: "look",
label: t("common.look_and_feel"),
href: `${basePath}/workspace/look`,
icon: <BrushIcon className={iconClassName} />,
id: "teams",
label: t("common.team_access"),
href: `${basePath}/workspace/teams`,
icon: <UsersIcon className={iconClassName} />,
disabled: isBilling,
},
{
id: "languages",
label: t("common.survey_languages"),
href: `${basePath}/workspace/languages`,
icon: <LanguagesIcon className={iconClassName} />,
disabled: isBilling,
},
{
id: "app-connection",
label: t("common.website_and_app_connection"),
label: t("common.connect_your_app"),
href: `${basePath}/workspace/app-connection`,
icon: <ListChecksIcon className={iconClassName} />,
disabled: isBilling,
@@ -276,17 +283,17 @@ export const SettingsSidebarContent = ({
disabled: isBilling,
},
{
id: "teams",
label: t("common.team_access"),
href: `${basePath}/workspace/teams`,
icon: <UsersIcon className={iconClassName} />,
id: "look",
label: t("common.appearance"),
href: `${basePath}/workspace/look`,
icon: <BrushIcon className={iconClassName} />,
disabled: isBilling,
},
{
id: "languages",
label: t("common.survey_languages"),
href: `${basePath}/workspace/languages`,
icon: <LanguagesIcon className={iconClassName} />,
id: "user-actions",
label: t("common.user_actions"),
href: `${basePath}/workspace/user-actions`,
icon: <ListChecksIcon className={iconClassName} />,
disabled: isBilling,
},
{
@@ -308,7 +315,7 @@ export const SettingsSidebarContent = ({
},
{
id: "org-teams",
label: t("common.members_and_teams"),
label: t("common.teams"),
href: `${basePath}/organization/teams`,
icon: <UsersIcon className={iconClassName} />,
disabled: isBilling,
@@ -347,7 +354,7 @@ export const SettingsSidebarContent = ({
const accountItems: NavItem[] = [
{
id: "profile",
label: t("common.profile"),
label: t("common.your_profile"),
href: `${basePath}/account/profile`,
icon: <UserCircleIcon className={iconClassName} />,
},
@@ -380,42 +387,48 @@ export const SettingsSidebarContent = ({
};
return (
<div className="flex flex-col gap-1 overflow-y-auto">
<SectionHeader
icon={<FoldersIcon className="h-4 w-4" />}
label={t("common.workspace")}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
switcherName={workspaceName}
switcherItems={workspaces}
isLoadingSwitcher={isLoadingWorkspaces}
currentId={workspaceId}
onSwitcherChange={onWorkspaceChange}
onSwitcherOpen={onWorkspaceDropdownOpen}
/>
{renderSection(workspaceItems)}
<div className="flex flex-col overflow-y-auto">
<div>
<SectionHeader
icon={<FoldersIcon className="h-4 w-4" />}
label={t("common.workspace")}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
switcherName={workspaceName}
switcherItems={workspaces}
isLoadingSwitcher={isLoadingWorkspaces}
currentId={workspaceId}
onSwitcherChange={onWorkspaceChange}
onSwitcherOpen={onWorkspaceDropdownOpen}
/>
{renderSection(workspaceItems)}
</div>
<SectionHeader
icon={<Building2Icon className="h-4 w-4" />}
label={t("common.organization")}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
switcherName={organizationName}
switcherItems={organizations}
isLoadingSwitcher={isLoadingOrganizations}
currentId={organizationId}
onSwitcherChange={onOrganizationChange}
onSwitcherOpen={onOrganizationDropdownOpen}
/>
{renderSection(organizationItems)}
<div>
<SectionHeader
icon={<Building2Icon className="h-4 w-4" />}
label={t("common.organization")}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
switcherName={organizationName}
switcherItems={organizations}
isLoadingSwitcher={isLoadingOrganizations}
currentId={organizationId}
onSwitcherChange={onOrganizationChange}
onSwitcherOpen={onOrganizationDropdownOpen}
/>
{renderSection(organizationItems)}
</div>
<SectionHeader
icon={<UserCircleIcon className="h-4 w-4" />}
label={t("common.account")}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
/>
{renderSection(accountItems)}
<div>
<SectionHeader
icon={<UserCircleIcon className="h-4 w-4" />}
label={t("common.account")}
isCollapsed={isCollapsed}
isTextVisible={isTextVisible}
/>
{renderSection(accountItems)}
</div>
</div>
);
};
@@ -37,16 +37,6 @@ interface WorkspaceBreadcrumbProps {
isMembershipPending: boolean;
}
const isActiveWorkspaceSetting = (pathname: string, settingId: string): boolean => {
// Match /{settingId} or /{settingId}/... but exclude settings paths
if (pathname.includes("/settings/")) {
return false;
}
// Check if path matches /workspaces/{id}/{settingId} (with optional trailing path)
const pattern = new RegExp(`/workspaces/[^/]+/${settingId}(?:/|$)`);
return pattern.test(pathname);
};
export const WorkspaceBreadcrumb = ({
currentWorkspaceId,
currentWorkspaceName,
@@ -106,17 +96,17 @@ export const WorkspaceBreadcrumb = ({
{
id: "general",
label: t("common.general"),
href: `${workspaceBasePath}/general`,
href: `${workspaceBasePath}/settings/workspace/general`,
},
{
id: "look",
label: t("common.look_and_feel"),
href: `${workspaceBasePath}/look`,
label: t("common.appearance"),
href: `${workspaceBasePath}/settings/workspace/look`,
},
{
id: "app-connection",
label: t("common.website_and_app_connection"),
href: `${workspaceBasePath}/app-connection`,
label: t("common.connect_your_app"),
href: `${workspaceBasePath}/settings/workspace/app-connection`,
},
{
id: "feedback-sources",
@@ -126,27 +116,27 @@ export const WorkspaceBreadcrumb = ({
{
id: "integrations",
label: t("common.integrations"),
href: `${workspaceBasePath}/integrations`,
href: `${workspaceBasePath}/settings/workspace/integrations`,
},
{
id: "teams",
label: t("common.team_access"),
href: `${workspaceBasePath}/teams`,
href: `${workspaceBasePath}/settings/workspace/teams`,
},
{
id: "languages",
label: t("common.survey_languages"),
href: `${workspaceBasePath}/languages`,
href: `${workspaceBasePath}/settings/workspace/languages`,
},
{
id: "tags",
label: t("common.tags"),
href: `${workspaceBasePath}/tags`,
href: `${workspaceBasePath}/settings/workspace/tags`,
},
{
id: "unify",
label: t("common.unify"),
href: `${workspaceBasePath}/workspace/unify`,
href: `${workspaceBasePath}/settings/workspace/unify`,
},
];
@@ -181,9 +171,9 @@ export const WorkspaceBreadcrumb = ({
setOpenCreateWorkspaceModal(true);
};
const handleWorkspaceSettingsNavigation = (settingId: string) => {
const handleWorkspaceSettingsNavigation = (href: string) => {
startTransition(() => {
router.push(`${workspaceBasePath}/${settingId}`);
router.push(href);
});
};
@@ -320,8 +310,8 @@ export const WorkspaceBreadcrumb = ({
</Popover>
) : (
<DropdownMenuCheckboxItem
checked={isActiveWorkspaceSetting(pathname, setting.id)}
onClick={() => handleWorkspaceSettingsNavigation(setting.id)}
checked={pathname.includes(setting.href)}
onClick={() => handleWorkspaceSettingsNavigation(setting.href)}
className="cursor-pointer">
{setting.label}
</DropdownMenuCheckboxItem>
@@ -38,7 +38,7 @@ export const OrganizationSettingsNavbar = ({
},
{
id: "teams",
label: t("common.members_and_teams"),
label: t("common.teams"),
href: `${workspaceBasePath}/settings/organization/teams`,
current: pathname?.includes("/teams"),
},
@@ -0,0 +1,3 @@
import { UserActionsLoading } from "@/modules/workspaces/settings/(setup)/user-actions/loading";
export default UserActionsLoading;
@@ -0,0 +1,3 @@
import { UserActionsPage } from "@/modules/workspaces/settings/(setup)/user-actions/page";
export default UserActionsPage;
+6 -3
View File
@@ -118,6 +118,7 @@ checksums:
common/api_keys: f961b547cd312cc8b9b79f0c9e0b2cc3
common/app: 77e32ac4e5a1e01bc9a6a15fdfef9bf8
common/app_survey: f076d131d20bfdadb35fba29c8275232
common/appearance: cdd8c41c5fb859234e8a603544fce631
common/apply_filters: 6543c1e80038b3da0f4a42848d08d4d1
common/archived: cf5127ecfd7e43a35466a1ba5fe16450
common/are_you_sure: 6d5cd13628a7887711fd0c29f1123652
@@ -152,6 +153,7 @@ checksums:
common/confirm: 90930b51154032f119fa75c1bd422d8b
common/connect: 8778ee245078a8be4a2ce855c8c56edc
common/connect_formbricks: a9dd747575e7e035da69251366df6f95
common/connect_your_app: 347e3bd3bdfc4a4e9d037ba837f3a48c
common/connected: aa0ceca574641de34c74b9e590664230
common/contact: 9afa39bc47019ee6dec6c74b6273967c
common/contacts: d5b6c3f890b3904eaf5754081945c03d
@@ -269,11 +271,9 @@ checksums:
common/loading: c6bc8c380e83336c81a92594d3f23000
common/logo: 47fa6b3978c1c06acc29b6cae393b0c9
common/logout: 07948fdf20705e04a7bf68ab197512bf
common/look_and_feel: 9125503712626d495cedec7a79f1418c
common/manage: a3d40c0267b81ae53c9598eaeb05087d
common/marketing: fcf0f06f8b64b458c7ca6d95541a3cc8
common/members: 0932e80cba1e3e0a7f52bb67ff31da32
common/members_and_teams: bf5c3fadcb9fc23533ec1532b805ac08
common/membership: 83c856bbc2af99d8c3d860959d1d2a85
common/membership_not_found: 7ac63584af23396aace9992ad919ffd4
common/meta: 842eac888f134f3525f8ea613d933687
@@ -324,6 +324,7 @@ checksums:
common/or: 7b133c38bec0d5ee23cc6bcf9a8de50b
common/organization: 3dc8489af7e74121f65ce6d9677bc94d
common/organization_id: ef09b71c84a25b5da02a23c77e68a335
common/organization_settings: 11528aa89ae9935e55dcb54478058775
common/other: 79acaa6cd481262bea4e743a422529d2
common/other_filters: 20b09213c131db47eb8b23e72d0c4bea
common/other_placeholder: f3a0fa2eaaf75aa92b290449c928c081
@@ -449,6 +450,7 @@ checksums:
common/trial_one_day_remaining: 2d64d39fca9589c4865357817bcc24d5
common/try_again: 33dd8820e743e35a66e6977f69e9d3b5
common/type: f04471a7ddac844b9ad145eb9911ef75
common/unify: bdb518a1e62f51049ccc4366b909fb0a
common/unknown_survey: dd8f6985e17ccf19fac1776e18b2c498
common/unlock_more_workspaces_with_a_higher_plan: fe1590075b855bb4306c9388b65143b0
common/update: 079fc039262fd31b10532929685c2d1b
@@ -460,6 +462,7 @@ checksums:
common/upload_input_description: 64f59bc339568d52b8464b82546b70ea
common/url: ca97457614226960d41dd18c3c29c86b
common/user: 61073457a5c3901084b557d065f876be
common/user_actions: 568ddeca3c5969341af83ff43f162233
common/user_id: 37f5ba37f71cb50607af32a6a203b1d4
common/variable: c13db5775ba9791b1522cc55c9c7acce
common/variable_ids: 44bf93b70703b7699fa9f21bc6c8eed4
@@ -471,7 +474,6 @@ checksums:
common/we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable: f29f2e0286195dab170b9806bcd74fc9
common/webhook: 70f95b2c27f2c3840b500fcaf79ee83c
common/webhooks: 0329bc102d3ab3c73410d126e119de12
common/website_and_app_connection: 60fea5cff5bddb4db3c8a1b0a2f9ec63
common/website_app_survey: 258579927ed3955dcc8e1cbd7f0df17f
common/website_survey: 17513d25a07b6361768a15ec622b021b
common/weeks: 545de30df4f44d3f6d1d344af6a10815
@@ -493,6 +495,7 @@ checksums:
common/you_have_reached_your_monthly_response_limit_of: 3824db23ecc3dcd2b1787b98ccfdd5f9
common/you_will_be_downgraded_to_the_community_edition_on_date: bff35b54c13e2c205dc4c19056261cc0
common/your_license_has_expired_please_renew: 3f21ae4a7deab351b143b407ece58254
common/your_profile: 955b66d0455e28c805cc462b8f8d1f11
emails/accept: f8cc1de4f5e3c850cfdbbc0ec831ade7
emails/click_or_drag_to_upload_files: 64f59bc339568d52b8464b82546b70ea
emails/email_customization_preview_email_heading: 8b798cb8438b3dd356c02dab33b4c897
+6 -5
View File
@@ -145,6 +145,7 @@
"api_keys": "API-Schlüssel",
"app": "App",
"app_survey": "App-Umfrage",
"appearance": "Erscheinungsbild",
"apply_filters": "Filter anwenden",
"archived": "Archiviert",
"are_you_sure": "Bist du sicher?",
@@ -176,10 +177,10 @@
"collapse_rows": "Zeilen einklappen",
"column_n": "Spalte {n}",
"completed": "Abgeschlossen",
"configuration": "Konfigurieren",
"confirm": "Bestätigen",
"connect": "Verbinden",
"connect_formbricks": "Formbricks verbinden",
"connect_your_app": "Verbinde deine App",
"connected": "Verbunden",
"contact": "Kontakt",
"contacts": "Kontakte",
@@ -297,11 +298,9 @@
"loading": "Lädt",
"logo": "Logo",
"logout": "Abmelden",
"look_and_feel": "Erscheinungsbild",
"manage": "Verwalten",
"marketing": "Marketing",
"members": "Mitglieder",
"members_and_teams": "Mitglieder & Teams",
"membership": "Mitgliedschaft",
"membership_not_found": "Mitgliedschaft nicht gefunden",
"meta": "Meta",
@@ -490,6 +489,7 @@
"upload_input_description": "Klicke oder ziehe Dateien hierher, um sie hochzuladen.",
"url": "URL",
"user": "Benutzer",
"user_actions": "Benutzeraktionen",
"user_id": "Benutzer-ID",
"variable": "Variable",
"variable_ids": "Variablen-IDs",
@@ -501,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Wir konnten deine Lizenz nicht verifizieren, da der Lizenzserver nicht erreichbar ist.",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "Website- & App-Verbindung",
"website_app_survey": "Website- & App-Umfrage",
"website_survey": "Website-Umfrage",
"weeks": "Wochen",
@@ -513,6 +512,7 @@
"workspace_id": "Workspace-ID",
"workspace_name": "Workspace-Name",
"workspace_name_placeholder": "z. B. Formbricks",
"workspace_settings": "Arbeitsbereich-Einstellungen",
"workspaces": "Workspaces",
"years": "Jahre",
"yes": "Ja",
@@ -521,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Du hast dein Limit von {workspaceLimit} Workspaces erreicht.",
"you_have_reached_your_monthly_response_limit_of": "Du hast dein monatliches Antwortlimit erreicht von",
"you_will_be_downgraded_to_the_community_edition_on_date": "Du wirst am {date} auf die Community Edition herabgestuft.",
"your_license_has_expired_please_renew": "Deine Enterprise-Lizenz ist abgelaufen. Bitte erneuere sie, um weiterhin Enterprise-Funktionen nutzen zu können."
"your_license_has_expired_please_renew": "Deine Enterprise-Lizenz ist abgelaufen. Bitte erneuere sie, um weiterhin Enterprise-Funktionen nutzen zu können.",
"your_profile": "Dein Profil"
},
"emails": {
"accept": "Akzeptieren",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "API Keys",
"app": "App",
"app_survey": "App Survey",
"appearance": "Appearance",
"apply_filters": "Apply filters",
"archived": "Archived",
"are_you_sure": "Are you sure?",
@@ -179,6 +180,7 @@
"confirm": "Confirm",
"connect": "Connect",
"connect_formbricks": "Connect Formbricks",
"connect_your_app": "Connect Your App",
"connected": "Connected",
"contact": "Contact",
"contacts": "Contacts",
@@ -296,11 +298,9 @@
"loading": "Loading",
"logo": "Logo",
"logout": "Logout",
"look_and_feel": "Look & Feel",
"manage": "Manage",
"marketing": "Marketing",
"members": "Members",
"members_and_teams": "Members & Teams",
"membership": "Membership",
"membership_not_found": "Membership not found",
"meta": "Meta",
@@ -351,6 +351,7 @@
"or": "or",
"organization": "Organization",
"organization_id": "Organization ID",
"organization_settings": "Organization settings",
"other": "Other",
"other_filters": "Other Filters",
"other_placeholder": "Other Placeholder",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "1 day left in your trial",
"try_again": "Try again",
"type": "Type",
"unify": "Unify",
"unknown_survey": "Unknown survey",
"unlock_more_workspaces_with_a_higher_plan": "Unlock more workspaces with a higher plan.",
"update": "Update",
@@ -487,6 +489,7 @@
"upload_input_description": "Click or drag to upload files.",
"url": "URL",
"user": "User",
"user_actions": "User Actions",
"user_id": "User ID",
"variable": "Variable",
"variable_ids": "Variable IDs",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "We were unable to verify your license because the license server is unreachable.",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "Website & App Connection",
"website_app_survey": "Website & App Survey",
"website_survey": "Website Survey",
"weeks": "weeks",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "You have reached your limit of {workspaceLimit} workspaces.",
"you_have_reached_your_monthly_response_limit_of": "You have reached your monthly response limit of",
"you_will_be_downgraded_to_the_community_edition_on_date": "You will be downgraded to the Community Edition on {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Your Profile"
},
"emails": {
"accept": "Accept",
+7 -6
View File
@@ -145,6 +145,7 @@
"api_keys": "Claves API",
"app": "Aplicación",
"app_survey": "Encuesta de aplicación",
"appearance": "Apariencia",
"apply_filters": "Aplicar filtros",
"archived": "Archivado",
"are_you_sure": "¿Estás seguro?",
@@ -176,10 +177,10 @@
"collapse_rows": "Contraer filas",
"column_n": "Columna {n}",
"completed": "Completado",
"configuration": "Configurar",
"confirm": "Confirmar",
"connect": "Conectar",
"connect_formbricks": "Conectar Formbricks",
"connect_your_app": "Conecta tu aplicación",
"connected": "Conectado",
"contact": "Contacto",
"contacts": "Contactos",
@@ -297,11 +298,9 @@
"loading": "Cargando",
"logo": "Logo",
"logout": "Cerrar sesión",
"look_and_feel": "Apariencia",
"manage": "Gestionar",
"marketing": "Marketing",
"members": "Miembros",
"members_and_teams": "Miembros y equipos",
"membership": "Membresía",
"membership_not_found": "Membresía no encontrada",
"meta": "Meta",
@@ -352,7 +351,7 @@
"or": "o",
"organization": "Organización",
"organization_id": "ID de organización",
"organization_settings": "Ajustes de la organización",
"organization_settings": "Configuración de la organización",
"other": "Otro",
"other_filters": "Otros Filtros",
"other_placeholder": "Otro marcador de posición",
@@ -490,6 +489,7 @@
"upload_input_description": "Haz clic o arrastra para subir archivos.",
"url": "URL",
"user": "Usuario",
"user_actions": "Acciones del usuario",
"user_id": "ID de usuario",
"variable": "Variable",
"variable_ids": "IDs de variables",
@@ -501,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "No pudimos verificar tu licencia porque el servidor de licencias no está accesible.",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "Conexión de sitio web y aplicación",
"website_app_survey": "Encuesta de sitio web y aplicación",
"website_survey": "Encuesta de sitio web",
"weeks": "semanas",
@@ -513,6 +512,7 @@
"workspace_id": "ID del espacio de trabajo",
"workspace_name": "Nombre del espacio de trabajo",
"workspace_name_placeholder": "p. ej. Formbricks",
"workspace_settings": "Configuración del espacio de trabajo",
"workspaces": "Espacios de trabajo",
"years": "años",
"yes": "Sí",
@@ -521,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Has alcanzado tu límite de {workspaceLimit} espacios de trabajo.",
"you_have_reached_your_monthly_response_limit_of": "Has alcanzado tu límite mensual de respuestas de",
"you_will_be_downgraded_to_the_community_edition_on_date": "Serás degradado a la edición Community el {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Tu perfil"
},
"emails": {
"accept": "Aceptar",
+6 -5
View File
@@ -145,6 +145,7 @@
"api_keys": "Clés API",
"app": "Application",
"app_survey": "Sondage d'application",
"appearance": "Apparence",
"apply_filters": "Appliquer des filtres",
"archived": "Archivé",
"are_you_sure": "Es-tu sûr ?",
@@ -176,10 +177,10 @@
"collapse_rows": "Réduire les lignes",
"column_n": "Colonne {n}",
"completed": "Terminé",
"configuration": "Configurer",
"confirm": "Confirmer",
"connect": "Connecter",
"connect_formbricks": "Connecter Formbricks",
"connect_your_app": "Connecter votre application",
"connected": "Connecté",
"contact": "Contact",
"contacts": "Contacts",
@@ -297,11 +298,9 @@
"loading": "Chargement",
"logo": "Logo",
"logout": "Déconnexion",
"look_and_feel": "Apparence",
"manage": "Gérer",
"marketing": "Marketing",
"members": "Membres",
"members_and_teams": "Membres & Équipes",
"membership": "Adhésion",
"membership_not_found": "Abonnement non trouvé",
"meta": "Méta",
@@ -490,6 +489,7 @@
"upload_input_description": "Cliquez ou faites glisser pour charger un fichier.",
"url": "URL",
"user": "Utilisateur",
"user_actions": "Actions utilisateur",
"user_id": "Identifiant d'utilisateur",
"variable": "Variable",
"variable_ids": "Identifiants variables",
@@ -501,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Nous n'avons pas pu vérifier votre licence car le serveur de licence est inaccessible.",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "Connexion de sites Web et d'applications",
"website_app_survey": "Sondage sur le site Web et l'application",
"website_survey": "Sondage de site web",
"weeks": "semaines",
@@ -513,6 +512,7 @@
"workspace_id": "ID de l'espace de travail",
"workspace_name": "Nom de l'espace de travail",
"workspace_name_placeholder": "par ex. Formbricks",
"workspace_settings": "Paramètres de l'espace de travail",
"workspaces": "Espaces de travail",
"years": "années",
"yes": "Oui",
@@ -521,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Vous avez atteint votre limite de {workspaceLimit} espaces de travail.",
"you_have_reached_your_monthly_response_limit_of": "Vous avez atteint votre limite de réponses mensuelle de",
"you_will_be_downgraded_to_the_community_edition_on_date": "Vous serez rétrogradé à l'édition communautaire le {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Votre profil"
},
"emails": {
"accept": "Accepter",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "API-kulcsok",
"app": "Alkalmazás",
"app_survey": "Alkalmazás-kérdőív",
"appearance": "Megjelenés",
"apply_filters": "Szűrők alkalmazása",
"archived": "Archivált",
"are_you_sure": "Biztos benne?",
@@ -179,6 +180,7 @@
"confirm": "Megerősítés",
"connect": "Kapcsolódás",
"connect_formbricks": "Kapcsolódás a Formbrickshez",
"connect_your_app": "Csatlakoztassa az Alkalmazását",
"connected": "Kapcsolódva",
"contact": "Kapcsolat",
"contacts": "Partnerek",
@@ -296,11 +298,9 @@
"loading": "Betöltés",
"logo": "Logó",
"logout": "Kijelentkezés",
"look_and_feel": "Megjelenés",
"manage": "Kezelés",
"marketing": "Marketing",
"members": "Tagok",
"members_and_teams": "Tagok és csapatok",
"membership": "Tagság",
"membership_not_found": "A tagság nem található",
"meta": "Meta",
@@ -351,6 +351,7 @@
"or": "vagy",
"organization": "Szervezet",
"organization_id": "Szervezetazonosító",
"organization_settings": "Szervezeti beállítások",
"other": "Egyéb",
"other_filters": "Egyéb szűrők",
"other_placeholder": "Egyéb helyőrző",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "1 nap van hátra a próbaidőszakából",
"try_again": "Próbálja újra",
"type": "Típus",
"unify": "Egyesítés",
"unknown_survey": "Ismeretlen kérdőív",
"unlock_more_workspaces_with_a_higher_plan": "Több munkaterület feloldása egy magasabb csomaggal.",
"update": "Frissítés",
@@ -487,6 +489,7 @@
"upload_input_description": "Kattintson vagy húzza ide a fájlok feltöltéséhez.",
"url": "URL",
"user": "Felhasználó",
"user_actions": "Felhasználói Műveletek",
"user_id": "Felhasználó-azonosító",
"variable": "Változó",
"variable_ids": "Változóazonosítók",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Nem tudtuk ellenőrizni a licencét, mert a licenckiszolgáló nem érhető el.",
"webhook": "Webhorog",
"webhooks": "Webhorgok",
"website_and_app_connection": "Webhely és alkalmazáskapcsolódás",
"website_app_survey": "Webhely és alkalmazás-kérdőív",
"website_survey": "Webhely kérdőív",
"weeks": "hét",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Elérte a munkaterületek {workspaceLimit} darabos korlátját.",
"you_have_reached_your_monthly_response_limit_of": "Elérte a havi válaszkorlátját ennek:",
"you_will_be_downgraded_to_the_community_edition_on_date": "Vissza lesz állítva a közösségi kiadásra ekkor: {date}.",
"your_license_has_expired_please_renew": "A vállalati licence lejárt. Újítsa meg, hogy továbbra is használhassa a vállalati funkciókat."
"your_license_has_expired_please_renew": "A vállalati licence lejárt. Újítsa meg, hogy továbbra is használhassa a vállalati funkciókat.",
"your_profile": "Az Ön Profilja"
},
"emails": {
"accept": "Elfogadás",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "APIキー",
"app": "アプリ",
"app_survey": "アプリ内フォーム",
"appearance": "外観",
"apply_filters": "フィルターを適用",
"archived": "アーカイブ済み",
"are_you_sure": "よろしいですか?",
@@ -179,6 +180,7 @@
"confirm": "確認",
"connect": "接続",
"connect_formbricks": "Formbricksを接続",
"connect_your_app": "アプリを接続",
"connected": "接続済み",
"contact": "連絡先",
"contacts": "連絡先",
@@ -296,11 +298,9 @@
"loading": "読み込み中",
"logo": "ロゴ",
"logout": "ログアウト",
"look_and_feel": "デザイン",
"manage": "管理",
"marketing": "マーケティング",
"members": "メンバー",
"members_and_teams": "メンバー&チーム",
"membership": "メンバーシップ",
"membership_not_found": "メンバーシップが見つかりません",
"meta": "メタ",
@@ -351,6 +351,7 @@
"or": "または",
"organization": "組織",
"organization_id": "組織ID",
"organization_settings": "組織設定",
"other": "その他",
"other_filters": "その他のフィルター",
"other_placeholder": "その他のプレースホルダー",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "トライアル期間の残り1日",
"try_again": "もう一度お試しください",
"type": "種類",
"unify": "統合",
"unknown_survey": "不明なフォーム",
"unlock_more_workspaces_with_a_higher_plan": "上位プランでより多くのワークスペースを利用できます。",
"update": "更新",
@@ -487,6 +489,7 @@
"upload_input_description": "クリックまたはドラッグしてファイルをアップロードしてください。",
"url": "URL",
"user": "ユーザー",
"user_actions": "ユーザーアクション",
"user_id": "ユーザーID",
"variable": "変数",
"variable_ids": "変数ID",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "ライセンスサーバーにアクセスできないため、ライセンスを認証できませんでした。",
"webhook": "Webhook",
"webhooks": "Webhook",
"website_and_app_connection": "ウェブサイト&アプリ接続",
"website_app_survey": "ウェブサイト&アプリフォーム",
"website_survey": "ウェブサイトフォーム",
"weeks": "週間",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "ワークスペースの上限である{workspaceLimit}件に達しました。",
"you_have_reached_your_monthly_response_limit_of": "月間回答数の上限に達しました",
"you_will_be_downgraded_to_the_community_edition_on_date": "コミュニティ版へのダウングレードは {date} に行われます。",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "あなたのプロフィール"
},
"emails": {
"accept": "承認",
+7 -6
View File
@@ -145,6 +145,7 @@
"api_keys": "API-sleutels",
"app": "App",
"app_survey": "App-enquête",
"appearance": "Weergave",
"apply_filters": "Pas filters toe",
"archived": "Gearchiveerd",
"are_you_sure": "Weet je het zeker?",
@@ -176,10 +177,10 @@
"collapse_rows": "Rijen samenvouwen",
"column_n": "Kolom {n}",
"completed": "Voltooid",
"configuration": "Configureren",
"confirm": "Bevestigen",
"connect": "Verbinden",
"connect_formbricks": "Sluit Formbricks aan",
"connect_your_app": "Verbind je app",
"connected": "Aangesloten",
"contact": "Contact",
"contacts": "Contacten",
@@ -297,11 +298,9 @@
"loading": "Laden",
"logo": "Logo",
"logout": "Uitloggen",
"look_and_feel": "Kijk & voel",
"manage": "Beheren",
"marketing": "Marketing",
"members": "Leden",
"members_and_teams": "Leden & teams",
"membership": "Lidmaatschap",
"membership_not_found": "Lidmaatschap niet gevonden",
"meta": "Meta",
@@ -478,7 +477,7 @@
"trial_one_day_remaining": "1 dag over in je proefperiode",
"try_again": "Probeer het opnieuw",
"type": "Type",
"unify": "Verenigen",
"unify": "Samenvoegen",
"unknown_survey": "Onbekende enquête",
"unlock_more_workspaces_with_a_higher_plan": "Ontgrendel meer werkruimtes met een hoger abonnement.",
"update": "Update",
@@ -490,6 +489,7 @@
"upload_input_description": "Klik of sleep om bestanden te uploaden.",
"url": "URL",
"user": "Gebruiker",
"user_actions": "Gebruikersacties",
"user_id": "Gebruikers-ID",
"variable": "Variabel",
"variable_ids": "Variabele ID's",
@@ -501,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "We kunnen uw licentie niet verifiëren omdat de licentieserver niet bereikbaar is.",
"webhook": "Webhook",
"webhooks": "Webhaken",
"website_and_app_connection": "Website- en app-verbinding",
"website_app_survey": "Website- en app-enquête",
"website_survey": "Website-enquête",
"weeks": "weken",
@@ -513,6 +512,7 @@
"workspace_id": "Werkruimte-ID",
"workspace_name": "Werkruimtenaam",
"workspace_name_placeholder": "bijv. Formbricks",
"workspace_settings": "Workspace-instellingen",
"workspaces": "Werkruimtes",
"years": "jaren",
"yes": "Ja",
@@ -521,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Je hebt je limiet van {workspaceLimit} workspaces bereikt.",
"you_have_reached_your_monthly_response_limit_of": "U heeft uw maandelijkse responslimiet bereikt van",
"you_will_be_downgraded_to_the_community_edition_on_date": "Je wordt gedowngraded naar de Community-editie op {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Jouw profiel"
},
"emails": {
"accept": "Accepteren",
+7 -6
View File
@@ -145,6 +145,7 @@
"api_keys": "Chaves de API",
"app": "app",
"app_survey": "Pesquisa de App",
"appearance": "Aparência",
"apply_filters": "Aplicar filtros",
"archived": "Arquivado",
"are_you_sure": "Certeza?",
@@ -176,10 +177,10 @@
"collapse_rows": "Recolher linhas",
"column_n": "Coluna {n}",
"completed": "Concluído",
"configuration": "Configurar",
"confirm": "Confirmar",
"connect": "Conectar",
"connect_formbricks": "Conectar Formbricks",
"connect_your_app": "Conecte Seu App",
"connected": "conectado",
"contact": "Contato",
"contacts": "Contatos",
@@ -297,11 +298,9 @@
"loading": "Carregando",
"logo": "Em breve",
"logout": "Sair",
"look_and_feel": "Aparência e Experiência",
"manage": "gerenciar",
"marketing": "marketing",
"members": "Membros",
"members_and_teams": "Membros e equipes",
"membership": "Associação",
"membership_not_found": "Assinatura não encontrada",
"meta": "Meta",
@@ -352,7 +351,7 @@
"or": "ou",
"organization": "organização",
"organization_id": "ID da Organização",
"organization_settings": "Configurações da Organização",
"organization_settings": "Configurações da organização",
"other": "outro",
"other_filters": "Outros Filtros",
"other_placeholder": "Outro espaço reservado",
@@ -490,6 +489,7 @@
"upload_input_description": "Clique ou arraste para fazer o upload de arquivos.",
"url": "URL",
"user": "Usuário",
"user_actions": "Ações do Usuário",
"user_id": "ID do usuário",
"variable": "variável",
"variable_ids": "IDs de variáveis",
@@ -501,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Não conseguimos verificar sua licença porque o servidor de licenças está inacessível.",
"webhook": "webhook",
"webhooks": "webhooks",
"website_and_app_connection": "Conexão de Site e App",
"website_app_survey": "Pesquisa de Site e App",
"website_survey": "Pesquisa de Site",
"weeks": "semanas",
@@ -513,6 +512,7 @@
"workspace_id": "ID do Workspace",
"workspace_name": "Nome do Workspace",
"workspace_name_placeholder": "ex: Formbricks",
"workspace_settings": "Configurações do Workspace",
"workspaces": "Workspaces",
"years": "anos",
"yes": "Sim",
@@ -521,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Você atingiu o limite de {workspaceLimit} espaços de trabalho.",
"you_have_reached_your_monthly_response_limit_of": "Você atingiu o limite mensal de respostas de",
"you_will_be_downgraded_to_the_community_edition_on_date": "Você será rebaixado para a Edição Comunitária em {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Seu Perfil"
},
"emails": {
"accept": "Aceitar",
+7 -6
View File
@@ -145,6 +145,7 @@
"api_keys": "Chaves API",
"app": "Aplicação",
"app_survey": "Inquérito (app)",
"appearance": "Aparência",
"apply_filters": "Aplicar filtros",
"archived": "Arquivado",
"are_you_sure": "Tem a certeza?",
@@ -176,10 +177,10 @@
"collapse_rows": "Recolher linhas",
"column_n": "Coluna {n}",
"completed": "Concluído",
"configuration": "Configurar",
"confirm": "Confirmar",
"connect": "Conectar",
"connect_formbricks": "Ligar Formbricks",
"connect_your_app": "Conecta a Tua App",
"connected": "Conectado",
"contact": "Contacto",
"contacts": "Contactos",
@@ -297,11 +298,9 @@
"loading": "A carregar",
"logo": "Logótipo",
"logout": "Terminar sessão",
"look_and_feel": "Aparência e Sensação",
"manage": "Gerir",
"marketing": "Marketing",
"members": "Membros",
"members_and_teams": "Membros e equipas",
"membership": "Subscrição",
"membership_not_found": "Associação não encontrada",
"meta": "Meta",
@@ -352,7 +351,7 @@
"or": "ou",
"organization": "Organização",
"organization_id": "ID da Organização",
"organization_settings": "Configurações da Organização",
"organization_settings": "Definições da organização",
"other": "Outro",
"other_filters": "Outros Filtros",
"other_placeholder": "Outro espaço reservado",
@@ -490,6 +489,7 @@
"upload_input_description": "Clique ou arraste para carregar ficheiros.",
"url": "URL",
"user": "Utilizador",
"user_actions": "Ações do Utilizador",
"user_id": "ID do Utilizador",
"variable": "Variável",
"variable_ids": "IDs de variáveis",
@@ -501,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Não foi possível verificar a sua licença porque o servidor de licenças está inacessível.",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "Ligação de Website e Aplicação",
"website_app_survey": "Inquérito do Website e da Aplicação",
"website_survey": "Inquérito do Website",
"weeks": "semanas",
@@ -513,6 +512,7 @@
"workspace_id": "ID do Espaço de Trabalho",
"workspace_name": "Nome do Espaço de Trabalho",
"workspace_name_placeholder": "ex. Formbricks",
"workspace_settings": "Definições da Área de Trabalho",
"workspaces": "Espaços de Trabalho",
"years": "anos",
"yes": "Sim",
@@ -521,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Atingiste o teu limite de {workspaceLimit} espaços de trabalho.",
"you_have_reached_your_monthly_response_limit_of": "Atingiu o seu limite mensal de respostas de",
"you_will_be_downgraded_to_the_community_edition_on_date": "Será rebaixado para a Edição Comunitária em {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "O Teu Perfil"
},
"emails": {
"accept": "Aceitar",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "Chei API",
"app": "Aplicație",
"app_survey": "Sondaj aplicație",
"appearance": "Aspect",
"apply_filters": "Aplică filtre",
"archived": "Arhivat",
"are_you_sure": "Ești sigur?",
@@ -179,6 +180,7 @@
"confirm": "Confirmare",
"connect": "Conectează",
"connect_formbricks": "Conectează Formbricks",
"connect_your_app": "Conectează-ți aplicația",
"connected": "Conectat",
"contact": "Contact",
"contacts": "Contacte",
@@ -296,11 +298,9 @@
"loading": "Încărcare",
"logo": "Logo",
"logout": "Deconectare",
"look_and_feel": "Aspect și Comportament",
"manage": "Gestionați",
"marketing": "Marketing",
"members": "Membri",
"members_and_teams": "Membri și echipe",
"membership": "Abonament",
"membership_not_found": "Apartenența nu a fost găsită",
"meta": "Meta",
@@ -351,6 +351,7 @@
"or": "sau",
"organization": "Organizație",
"organization_id": "ID Organizație",
"organization_settings": "Setări organizație",
"other": "Altele",
"other_filters": "Alte Filtre",
"other_placeholder": "Alt substituent",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "1 zi rămasă în perioada ta de probă",
"try_again": "Încearcă din nou",
"type": "Tip",
"unify": "Unifică",
"unknown_survey": "Chestionar necunoscut",
"unlock_more_workspaces_with_a_higher_plan": "Deblochează mai multe workspaces cu un plan superior.",
"update": "Actualizare",
@@ -487,6 +489,7 @@
"upload_input_description": "Faceți clic sau trageți pentru a încărca fișiere.",
"url": "URL",
"user": "Utilizator",
"user_actions": "Acțiuni utilizator",
"user_id": "ID Utilizator",
"variable": "Variabilă",
"variable_ids": "ID-uri variabile",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Nu am putut verifica licența dvs. deoarece serverul de licențe este inaccesibil.",
"webhook": "Webhook",
"webhooks": "Webhook-uri",
"website_and_app_connection": "Conectare site web și aplicație",
"website_app_survey": "Chestionar pentru site și aplicație",
"website_survey": "Chestionar despre site",
"weeks": "săptămâni",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Ai atins limita de {workspaceLimit} spații de lucru.",
"you_have_reached_your_monthly_response_limit_of": "Ați atins limita lunară de răspunsuri de",
"you_will_be_downgraded_to_the_community_edition_on_date": "Vei fi retrogradat la ediția Community pe {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Profilul tău"
},
"emails": {
"accept": "Acceptă",
+6 -5
View File
@@ -145,6 +145,7 @@
"api_keys": "API-ключи",
"app": "Приложение",
"app_survey": "Опрос о приложении",
"appearance": "Внешний вид",
"apply_filters": "Применить фильтры",
"archived": "Архивный",
"are_you_sure": "Вы уверены?",
@@ -176,10 +177,10 @@
"collapse_rows": "Свернуть строки",
"column_n": "Столбец {n}",
"completed": "Завершено",
"configuration": "Настроить",
"confirm": "Подтвердить",
"connect": "Подключить",
"connect_formbricks": "Подключить Formbricks",
"connect_your_app": "Подключи своё приложение",
"connected": "Подключено",
"contact": "Контакт",
"contacts": "Контакты",
@@ -297,11 +298,9 @@
"loading": "Загрузка",
"logo": "Логотип",
"logout": "Выйти",
"look_and_feel": "Внешний вид",
"manage": "Управление",
"marketing": "Маркетинг",
"members": "Участники",
"members_and_teams": "Участники и команды",
"membership": "Членство",
"membership_not_found": "Участие не найдено",
"meta": "Мета",
@@ -490,6 +489,7 @@
"upload_input_description": "Кликните или перетащите файлы для загрузки.",
"url": "URL",
"user": "Пользователь",
"user_actions": "Действия пользователя",
"user_id": "ID пользователя",
"variable": "Переменная",
"variable_ids": "ID переменных",
@@ -501,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Не удалось проверить вашу лицензию, так как сервер лицензий недоступен.",
"webhook": "Webhook",
"webhooks": "Webhook-и",
"website_and_app_connection": "Связь сайта и приложения",
"website_app_survey": "Опрос сайта и приложения",
"website_survey": "Опрос сайта",
"weeks": "недели",
@@ -513,6 +512,7 @@
"workspace_id": "ID рабочего пространства",
"workspace_name": "Название рабочего пространства",
"workspace_name_placeholder": "например, Formbricks",
"workspace_settings": "Настройки рабочего пространства",
"workspaces": "Рабочие пространства",
"years": "годы",
"yes": "Да",
@@ -521,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Вы достигли лимита в {workspaceLimit} рабочих пространств.",
"you_have_reached_your_monthly_response_limit_of": "Вы достигли месячного лимита ответов:",
"you_will_be_downgraded_to_the_community_edition_on_date": "Ваша версия будет понижена до Community Edition {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Твой профиль"
},
"emails": {
"accept": "Принять",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "API-nycklar",
"app": "App",
"app_survey": "App-enkät",
"appearance": "Utseende",
"apply_filters": "Tillämpa filter",
"archived": "Arkiverad",
"are_you_sure": "Är du säker?",
@@ -179,6 +180,7 @@
"confirm": "Bekräfta",
"connect": "Anslut",
"connect_formbricks": "Anslut Formbricks",
"connect_your_app": "Anslut din app",
"connected": "Ansluten",
"contact": "Kontakt",
"contacts": "Kontakter",
@@ -296,11 +298,9 @@
"loading": "Laddar",
"logo": "Logotyp",
"logout": "Logga ut",
"look_and_feel": "Utseende",
"manage": "Hantera",
"marketing": "Marknadsföring",
"members": "Medlemmar",
"members_and_teams": "Medlemmar och team",
"membership": "Medlemskap",
"membership_not_found": "Medlemskap hittades inte",
"meta": "Meta",
@@ -351,6 +351,7 @@
"or": "eller",
"organization": "Organisation",
"organization_id": "Organisations-ID",
"organization_settings": "Organisationsinställningar",
"other": "Annat",
"other_filters": "Andra filter",
"other_placeholder": "Annan platshållare",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "1 dag kvar av din provperiod",
"try_again": "Försök igen",
"type": "Typ",
"unify": "Förena",
"unknown_survey": "Okänd enkät",
"unlock_more_workspaces_with_a_higher_plan": "Lås upp fler arbetsytor med ett högre abonnemang.",
"update": "Uppdatera",
@@ -487,6 +489,7 @@
"upload_input_description": "Klicka eller dra för att ladda upp filer.",
"url": "URL",
"user": "Användare",
"user_actions": "Användaråtgärder",
"user_id": "Användar-ID",
"variable": "Variabel",
"variable_ids": "Variabel-ID:n",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Vi kunde inte verifiera din licens eftersom licensservern inte kan nås.",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "Webbplats- och appanslutning",
"website_app_survey": "Webbplats- och appenkät",
"website_survey": "Webbplatsenkät",
"weeks": "veckor",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "Du har nått din gräns på {workspaceLimit} arbetsytor.",
"you_have_reached_your_monthly_response_limit_of": "Du har nått din månatliga svarsgräns på",
"you_will_be_downgraded_to_the_community_edition_on_date": "Du kommer att nedgraderas till Community Edition den {date}.",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "Din profil"
},
"emails": {
"accept": "Acceptera",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "API Anahtarları",
"app": "Uygulama",
"app_survey": "Uygulama Anketi",
"appearance": "Görünüm",
"apply_filters": "Filtreleri uygula",
"archived": "Arşivlenmiş",
"are_you_sure": "Emin misiniz?",
@@ -179,6 +180,7 @@
"confirm": "Onayla",
"connect": "Bağlan",
"connect_formbricks": "Formbricks'i Bağla",
"connect_your_app": "Uygulamanı Bağla",
"connected": "Bağlı",
"contact": "Kişi",
"contacts": "Kişiler",
@@ -296,11 +298,9 @@
"loading": "Yükleniyor",
"logo": "Logo",
"logout": "Çıkış",
"look_and_feel": "Görünüm",
"manage": "Yönet",
"marketing": "Pazarlama",
"members": "Üyeler",
"members_and_teams": "Üyeler ve Takımlar",
"membership": "Üyelik",
"membership_not_found": "Üyelik bulunamadı",
"meta": "Meta",
@@ -351,6 +351,7 @@
"or": "veya",
"organization": "Organizasyon",
"organization_id": "Organizasyon ID",
"organization_settings": "Organizasyon ayarları",
"other": "Diğer",
"other_filters": "Diğer Filtreler",
"other_placeholder": "Diğer Yer Tutucu",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "Deneme sürenizde 1 gün kaldı",
"try_again": "Tekrar dene",
"type": "Tür",
"unify": "Birleştir",
"unknown_survey": "Bilinmeyen anket",
"unlock_more_workspaces_with_a_higher_plan": "Daha yüksek bir planla daha fazla çalışma alanının kilidini açın.",
"update": "Güncelle",
@@ -487,6 +489,7 @@
"upload_input_description": "Dosya yüklemek için tıklayın veya sürükleyin.",
"url": "URL",
"user": "Kullanıcı",
"user_actions": "Kullanıcı İşlemleri",
"user_id": "Kullanıcı ID",
"variable": "Değişken",
"variable_ids": "Değişken ID'leri",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "Lisans sunucusuna erişilemediği için lisansınızı doğrulayamadık.",
"webhook": "Webhook",
"webhooks": "Webhook'lar",
"website_and_app_connection": "Web Sitesi ve Uygulama Bağlantısı",
"website_app_survey": "Web Sitesi ve Uygulama Anketi",
"website_survey": "Web Sitesi Anketi",
"weeks": "hafta",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "{workspaceLimit} çalışma alanı limitine ulaştınız.",
"you_have_reached_your_monthly_response_limit_of": "Aylık yanıt sınırınıza ulaştınız:",
"you_will_be_downgraded_to_the_community_edition_on_date": "{date} tarihinde Topluluk Sürümüne düşürüleceksiniz.",
"your_license_has_expired_please_renew": "Kurumsal lisansınızın süresi doldu. Kurumsal özellikleri kullanmaya devam etmek için lütfen yenileyin."
"your_license_has_expired_please_renew": "Kurumsal lisansınızın süresi doldu. Kurumsal özellikleri kullanmaya devam etmek için lütfen yenileyin.",
"your_profile": "Profilin"
},
"emails": {
"accept": "Kabul Et",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "API 密钥",
"app": "应用",
"app_survey": "应用 程序 调查",
"appearance": "外观",
"apply_filters": "应用 筛选",
"archived": "已归档",
"are_you_sure": "你 确定 吗?",
@@ -179,6 +180,7 @@
"confirm": "确认",
"connect": "连接",
"connect_formbricks": "连接 Formbricks",
"connect_your_app": "连接您的应用",
"connected": "已连接",
"contact": "联系人",
"contacts": "联系人",
@@ -296,11 +298,9 @@
"loading": "加载",
"logo": "徽标",
"logout": "退出登录",
"look_and_feel": "外观 & 感觉",
"manage": "管理",
"marketing": "市场营销",
"members": "成员",
"members_and_teams": "成员和团队",
"membership": "会员资格",
"membership_not_found": "未找到会员资格",
"meta": "元数据",
@@ -351,6 +351,7 @@
"or": "或",
"organization": "组织",
"organization_id": "组织 ID",
"organization_settings": "组织设置",
"other": "其他",
"other_filters": "其他筛选条件",
"other_placeholder": "其他占位符",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "试用期还剩 1 天",
"try_again": "再试一次",
"type": "类型",
"unify": "统一",
"unknown_survey": "未知调查",
"unlock_more_workspaces_with_a_higher_plan": "升级套餐以解锁更多工作区。",
"update": "更新",
@@ -487,6 +489,7 @@
"upload_input_description": "点击 或 拖动 上传 文件",
"url": "URL",
"user": "用户",
"user_actions": "用户操作",
"user_id": "用户 ID",
"variable": "变量",
"variable_ids": "变量 ID",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "我们无法验证您的许可证,因为许可证服务器无法访问。",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "网站 & 应用程序 连接",
"website_app_survey": "网站 & 应用 调查",
"website_survey": "网站 调查",
"weeks": "周",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "您已达到 {workspaceLimit} 个工作区的上限。",
"you_have_reached_your_monthly_response_limit_of": "您 已经 达到 每月 的 响应 限制",
"you_will_be_downgraded_to_the_community_edition_on_date": "您将在 {date} 降级到社区版。",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "您的个人资料"
},
"emails": {
"accept": "接受",
+7 -4
View File
@@ -145,6 +145,7 @@
"api_keys": "API 金鑰",
"app": "應用程式",
"app_survey": "應用程式問卷",
"appearance": "外觀",
"apply_filters": "套用篩選器",
"archived": "已封存",
"are_you_sure": "您確定嗎?",
@@ -179,6 +180,7 @@
"confirm": "確認",
"connect": "連線",
"connect_formbricks": "連線 Formbricks",
"connect_your_app": "連接你的應用程式",
"connected": "已連線",
"contact": "聯絡人",
"contacts": "聯絡人",
@@ -296,11 +298,9 @@
"loading": "載入中",
"logo": "標誌",
"logout": "登出",
"look_and_feel": "外觀與風格",
"manage": "管理",
"marketing": "行銷",
"members": "成員",
"members_and_teams": "成員與團隊",
"membership": "會員資格",
"membership_not_found": "找不到成員資格",
"meta": "Meta",
@@ -351,6 +351,7 @@
"or": "或",
"organization": "組織",
"organization_id": "組織 ID",
"organization_settings": "組織設定",
"other": "其他",
"other_filters": "其他篩選條件",
"other_placeholder": "其他預設文字",
@@ -476,6 +477,7 @@
"trial_one_day_remaining": "試用期剩餘 1 天",
"try_again": "再試一次",
"type": "類型",
"unify": "統一",
"unknown_survey": "未知問卷",
"unlock_more_workspaces_with_a_higher_plan": "升級方案以解鎖更多工作區。",
"update": "更新",
@@ -487,6 +489,7 @@
"upload_input_description": "點擊或拖曳以上傳檔案。",
"url": "網址",
"user": "使用者",
"user_actions": "使用者操作",
"user_id": "使用者 ID",
"variable": "變數",
"variable_ids": "變數 ID",
@@ -498,7 +501,6 @@
"we_were_unable_to_verify_your_license_because_the_license_server_is_unreachable": "我們無法驗證您的授權,因為授權伺服器無法連線。",
"webhook": "Webhook",
"webhooks": "Webhooks",
"website_and_app_connection": "網站與應用程式連線",
"website_app_survey": "網站與應用程式問卷",
"website_survey": "網站問卷",
"weeks": "週",
@@ -519,7 +521,8 @@
"you_have_reached_your_limit_of_workspace_limit": "您已達到 {workspaceLimit} 個工作區的上限。",
"you_have_reached_your_monthly_response_limit_of": "您已達到每月回應上限:",
"you_will_be_downgraded_to_the_community_edition_on_date": "您將於 '{'date'}' 降級至社群版。",
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features."
"your_license_has_expired_please_renew": "Your enterprise license has expired. Please renew it to continue using enterprise features.",
"your_profile": "你的個人檔案"
},
"emails": {
"accept": "接受",
@@ -33,7 +33,7 @@ export const TeamsPage = async (props: { params: Promise<{ workspaceId: string }
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.members_and_teams")} />
<PageHeader pageTitle={t("common.teams")} />
<MembersView
membershipRole={currentUserMembership?.role}
organization={organization}
@@ -281,7 +281,7 @@ export const StylingView = ({
<p className="text-sm text-slate-500">
{t("workspace.surveys.edit.adjust_the_theme_in_the")}{" "}
<Link href={`${workspaceBasePath}/look`} target="_blank" className="font-semibold underline">
{t("common.look_and_feel")}
{t("common.appearance")}
</Link>{" "}
{t("common.settings")}
</p>
@@ -34,7 +34,7 @@ export const AppConnectionLoading = () => {
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.website_and_app_connection")} />
<PageHeader pageTitle={t("common.connect_your_app")} />
<div className="mt-4 flex max-w-4xl animate-pulse items-center space-y-4 rounded-lg border bg-blue-50 p-6 text-sm text-blue-900 shadow-sm md:space-y-0 md:text-base"></div>
{cards.map((card) => (
<LoadingCard key={card.title} {...card} />
@@ -3,16 +3,13 @@
import Link from "next/link";
import { WidgetStatusIndicator } from "@/app/(app)/workspaces/[workspaceId]/components/WidgetStatusIndicator";
import { SettingsCard } from "@/app/(app)/workspaces/[workspaceId]/settings/components/SettingsCard";
import { getActionClasses } from "@/lib/actionClass/service";
import { DEFAULT_LOCALE, WEBAPP_URL } from "@/lib/constants";
import { getUserLocale } from "@/lib/user/service";
import { WEBAPP_URL } from "@/lib/constants";
import { getTranslate } from "@/lingodotdev/server";
import { Alert, AlertButton, AlertDescription, AlertTitle } from "@/modules/ui/components/alert";
import { IdBadge } from "@/modules/ui/components/id-badge";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
import { getWorkspaceAuth } from "@/modules/workspaces/lib/utils";
import { ActionSettingsCard } from "../components/action-settings-card";
export const AppConnectionPage = async ({ params }: { params: Promise<{ workspaceId: string }> }) => {
const t = await getTranslate();
@@ -22,16 +19,11 @@ export const AppConnectionPage = async ({ params }: { params: Promise<{ workspac
const workspaceIdMigrationUrl =
"https://formbricks.com/docs/xm-and-surveys/surveys/website-app-surveys/workspace-id-migration";
const { isReadOnly, session, workspace } = await getWorkspaceAuth(workspaceId);
const [actionClasses, locale] = await Promise.all([
getActionClasses(workspace.id),
getUserLocale(session.user.id),
]);
const { workspace } = await getWorkspaceAuth(workspaceId);
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.website_and_app_connection")} />
<PageHeader pageTitle={t("common.connect_your_app")} />
<div className="space-y-4">
<SettingsCard
title={t("workspace.app-connection.sdk_connection_details")}
@@ -87,12 +79,6 @@ export const AppConnectionPage = async ({ params }: { params: Promise<{ workspac
</div>
)}
</SettingsCard>
<ActionSettingsCard
workspaceId={workspace.id}
actionClasses={actionClasses}
isReadOnly={isReadOnly}
locale={locale ?? DEFAULT_LOCALE}
/>
</div>
</PageContentWrapper>
);
@@ -0,0 +1,26 @@
"use client";
import { useTranslation } from "react-i18next";
import { LoadingCard } from "@/app/(app)/components/LoadingCard";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
export const UserActionsLoading = () => {
const { t } = useTranslation();
const cards = [
{
title: t("common.actions"),
description: t("common.actions_description"),
skeletonLines: [{ classes: "h-44 max-w-full rounded-lg" }],
},
];
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.user_actions")} />
{cards.map((card) => (
<LoadingCard key={card.title} {...card} />
))}
</PageContentWrapper>
);
};
@@ -0,0 +1,36 @@
"use server";
import { getActionClasses } from "@/lib/actionClass/service";
import { DEFAULT_LOCALE } from "@/lib/constants";
import { getUserLocale } from "@/lib/user/service";
import { getTranslate } from "@/lingodotdev/server";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
import { getWorkspaceAuth } from "@/modules/workspaces/lib/utils";
import { ActionSettingsCard } from "../components/action-settings-card";
export const UserActionsPage = async ({ params }: { params: Promise<{ workspaceId: string }> }) => {
const t = await getTranslate();
const { workspaceId } = await params;
const { isReadOnly, session, workspace } = await getWorkspaceAuth(workspaceId);
const [actionClasses, locale] = await Promise.all([
getActionClasses(workspace.id),
getUserLocale(session.user.id),
]);
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.user_actions")} />
<div className="space-y-4">
<ActionSettingsCard
workspaceId={workspace.id}
actionClasses={actionClasses}
isReadOnly={isReadOnly}
locale={locale ?? DEFAULT_LOCALE}
/>
</div>
</PageContentWrapper>
);
};
@@ -35,14 +35,14 @@ export const WorkspaceConfigNavigation = ({ activeId, loading }: WorkspaceConfig
},
{
id: "look",
label: t("common.look_and_feel"),
label: t("common.appearance"),
icon: <BrushIcon className="h-5 w-5" />,
href: `${workspaceBasePath}/settings/workspace/look`,
current: pathname?.includes("/look"),
},
{
id: "app-connection",
label: t("common.website_and_app_connection"),
label: t("common.connect_your_app"),
icon: <ListChecksIcon className="h-5 w-5" />,
href: `${workspaceBasePath}/settings/workspace/app-connection`,
current: pathname?.includes("/app-connection"),
@@ -23,7 +23,7 @@ export const WorkspaceLookSettingsLoading = () => {
];
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.look_and_feel")} />
<PageHeader pageTitle={t("common.appearance")} />
<SettingsCard
title={t("workspace.look.theme")}
className="max-w-7xl"
@@ -32,7 +32,7 @@ export const WorkspaceLookSettingsPage = async (props: { params: Promise<{ works
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.look_and_feel")} />
<PageHeader pageTitle={t("common.appearance")} />
{!IS_STORAGE_CONFIGURED && (
<Alert variant="warning">
<AlertDescription>{t("common.storage_not_configured")}</AlertDescription>