diff --git a/packages/constants/src/workspace.ts b/packages/constants/src/workspace.ts
index 8fd77cb572b..3bbb5b1f31f 100644
--- a/packages/constants/src/workspace.ts
+++ b/packages/constants/src/workspace.ts
@@ -121,7 +121,7 @@ export const WORKSPACE_SETTINGS = {
},
"api-tokens": {
key: "api-tokens",
- i18n_label: "workspace_settings.settings.webhooks.title",
+ i18n_label: "workspace_settings.settings.api_tokens.title",
href: `/settings/api-tokens`,
access: [EUserWorkspaceRoles.ADMIN],
highlight: (pathname: string, baseUrl: string) =>
diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json
index cab40f4fec0..6fc3f296aae 100644
--- a/packages/i18n/src/locales/en/translations.json
+++ b/packages/i18n/src/locales/en/translations.json
@@ -352,6 +352,17 @@
"no_labels_yet": "No labels yet",
"ideal": "Ideal",
"current": "Current",
+ "no_matching_members": "No matching members",
+ "leaving": "Leaving",
+ "removing": "Removing",
+ "leave": "Leave",
+ "refreshing": "Refreshing",
+ "refresh_status": "Refresh status",
+ "prev": "Prev",
+ "next": "Next",
+ "re_generating": "Re-generating",
+ "re_generate": "Re-generate",
+ "re_generate_key": "Re-generate key",
"project_view": {
"sort_by": {
@@ -895,24 +906,124 @@
"workspace_settings": {
"label": "Workspace settings",
+ "key_created": "Key created",
+ "copy_key": "Copy and save this secret key in Plane Pages. You can't see this key after you hit Close. A CSV file containing the key has been downloaded.",
+ "token_copied": "Token copied to clipboard.",
"settings": {
"general": {
- "title": "General"
+ "title": "General",
+ "upload_logo": "Upload logo",
+ "edit_logo": "Edit logo",
+ "name": "Workspace name",
+ "company_size": "Company size",
+ "url": "Workspace URL",
+ "update_workspace" : "Update workspace",
+ "delete_workspace" : "Delete workspace",
+ "delete_workspace_description" : "When deleting a workspace, all of the data and resources within that workspace will be permanently removed and cannot be recovered.",
+ "delete_btn": "Delete my workspace",
+ "errors": {
+ "name": {
+ "required": "Name is required",
+ "max_length": "Workspace name should not exceed 80 characters"
+ },
+ "company_size": {
+ "required": "Company size is required"
+ }
+ }
},
"members": {
- "title": "Members"
+ "title": "Members",
+ "add_member": "Add member",
+ "invitations_sent_successfully": "Invitations sent successfully",
+ "leave_confirmation": "Are you sure you want to leave the workspace? You will no longer have access to this workspace. This action cannot be undone.",
+ "details":{
+ "full_name":"Full name",
+ "display_name":"Display name",
+ "email_address":"Email address",
+ "account_type":"Account type",
+ "authentication":"Authentication",
+ "joining_date":"Joining date"
+ }
},
- "billing-and-plans": {
- "title": "Billing & Plans"
+ "billing_and_plans": {
+ "title": "Billing & Plans",
+ "current_plan":"Current plan",
+ "free_plan":"You are currently using the free plan",
+ "view_plans":"View plans"
},
"exports": {
- "title": "Exports"
+ "title": "Exports",
+ "exporting": "Exporting",
+ "previous_exports": "Previous exports",
+ "export_separate_files" : "Export the data into separate files",
+ "modal": {
+ "title": "Export to",
+ "toasts": {
+ "success": {
+ "title": "Export successful",
+ "message": "You will be able to download the exported {entity} from the previous export."
+ },
+ "error": {
+ "title": "Export failed",
+ "message": "Export was unsuccessful. Please try again."
+ }
+ }
+ }
},
"webhooks": {
- "title": "Webhooks"
+ "title": "Webhooks",
+ "add_webhook": "Add webhook",
+ "modal": {
+ "title": "Create webhook",
+ "details": "Webhook details",
+ "payload": "Payload URL",
+ "question": "Which events would you like to trigger this webhook?" ,
+ "error": "URL is required"
+ },
+ "secret_key": {
+ "title": "Secret key",
+ "message": "Generate a token to sign-in to the webhook payload"
+ },
+ "toasts": {
+ "created": {
+ "title": "Webhook created",
+ "message": "The webhook has been successfully created"
+ },
+ "not_created": {
+ "title": "Webhook not created",
+ "message": "The webhook could not be created"
+ },
+ "updated": {
+ "title": "Webhook updated",
+ "message": "The webhook has been successfully updated"
+ },
+ "not_updated": {
+ "title": "Webhook not updated",
+ "message": "The webhook could not be updated"
+ },
+ "removed": {
+ "title": "Webhook removed",
+ "message": "The webhook has been successfully removed"
+ },
+ "not_removed": {
+ "title": "Webhook not removed",
+ "message": "The webhook could not be removed"
+ },
+ "secret_key_copied": {
+ "message": "Secret key copied to clipboard."
+ },
+ "secret_key_not_copied": {
+ "message": "Error occurred while copying secret key."
+ }
+ }
},
- "api-tokens": {
- "title": "API Tokens"
+ "api_tokens": {
+ "title": "API Tokens",
+ "add_token": "Add API token",
+ "create_token": "Create token",
+ "never_expires": "Never expires",
+ "generate_token": "Generate token",
+ "generating": "Generating"
}
},
"empty_state": {
diff --git a/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx b/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx
index 03bb1fa6cbe..6c46a1d812a 100644
--- a/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx
+++ b/web/app/[workspaceSlug]/(projects)/settings/api-tokens/page.tsx
@@ -43,7 +43,9 @@ const ApiTokensPage = observer(() => {
workspaceSlug && canPerformWorkspaceAdminActions ? apiTokenService.getApiTokens(workspaceSlug.toString()) : null
);
- const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - API Tokens` : undefined;
+ const pageTitle = currentWorkspace?.name
+ ? `${currentWorkspace.name} - ${t("workspace_settings.settings.api_tokens.title")}`
+ : undefined;
if (workspaceUserInfo && !canPerformWorkspaceAdminActions) {
return ;
@@ -61,9 +63,9 @@ const ApiTokensPage = observer(() => {
{tokens.length > 0 ? (
<>
-
API tokens
+ {t("workspace_settings.settings.api_tokens.title")}
setIsCreateTokenModalOpen(true)}>
- Add API token
+ {t("workspace_settings.settings.api_tokens.add_token")}
@@ -75,9 +77,9 @@ const ApiTokensPage = observer(() => {
) : (
-
API tokens
+ {t("workspace_settings.settings.api_tokens.title")}
setIsCreateTokenModalOpen(true)}>
- Add API token
+ {t("workspace_settings.settings.api_tokens.add_token")}
diff --git a/web/app/[workspaceSlug]/(projects)/settings/exports/page.tsx b/web/app/[workspaceSlug]/(projects)/settings/exports/page.tsx
index dc3f3aafce7..0c6c26b377f 100644
--- a/web/app/[workspaceSlug]/(projects)/settings/exports/page.tsx
+++ b/web/app/[workspaceSlug]/(projects)/settings/exports/page.tsx
@@ -2,6 +2,7 @@
import { observer } from "mobx-react";
// components
+import { useTranslation } from "@plane/i18n";
import { NotAuthorizedView } from "@/components/auth-screens";
import { PageHead } from "@/components/core";
import ExportGuide from "@/components/exporter/guide";
@@ -15,13 +16,16 @@ const ExportsPage = observer(() => {
// store hooks
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
const { currentWorkspace } = useWorkspace();
+ const { t } = useTranslation();
// derived values
const canPerformWorkspaceMemberActions = allowPermissions(
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
EUserPermissionsLevel.WORKSPACE
);
- const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Exports` : undefined;
+ const pageTitle = currentWorkspace?.name
+ ? `${currentWorkspace.name} - ${t("workspace_settings.settings.exports.title")}`
+ : undefined;
// if user is not authorized to view this page
if (workspaceUserInfo && !canPerformWorkspaceMemberActions) {
@@ -37,7 +41,7 @@ const ExportsPage = observer(() => {
})}
>
-
Exports
+ {t("workspace_settings.settings.exports.title")}
diff --git a/web/app/[workspaceSlug]/(projects)/settings/members/page.tsx b/web/app/[workspaceSlug]/(projects)/settings/members/page.tsx
index 2b869612773..861548d23c7 100644
--- a/web/app/[workspaceSlug]/(projects)/settings/members/page.tsx
+++ b/web/app/[workspaceSlug]/(projects)/settings/members/page.tsx
@@ -6,6 +6,7 @@ import { useParams } from "next/navigation";
import { Search } from "lucide-react";
// types
import { MEMBER_INVITED } from "@plane/constants";
+import { useTranslation } from "@plane/i18n";
import { IWorkspaceBulkInviteFormData } from "@plane/types";
// ui
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
@@ -34,6 +35,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
workspace: { inviteMembersToWorkspace },
} = useMember();
const { currentWorkspace } = useWorkspace();
+ const { t } = useTranslation();
// derived values
const canPerformWorkspaceAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
@@ -62,7 +64,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Success!",
- message: "Invitations sent successfully.",
+ message: t("workspace_settings.settings.members.invitations_sent_successfully"),
});
})
.catch((err) => {
@@ -80,7 +82,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
setToast({
type: TOAST_TYPE.ERROR,
title: "Error!",
- message: `${err.error ?? "Something went wrong. Please try again."}`,
+ message: `${err.error ?? t("something_went_wrong_please_try_again")}`,
});
});
};
@@ -107,12 +109,12 @@ const WorkspaceMembersSettingsPage = observer(() => {
})}
>
-
Members
+
{t("workspace_settings.settings.members.title")}
setSearchQuery(e.target.value)}
@@ -120,7 +122,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
{canPerformWorkspaceAdminActions && (
setInviteModal(true)}>
- Add member
+ {t("workspace_settings.settings.members.add_member")}
)}
diff --git a/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx b/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx
index 8dfe7437938..c071622e601 100644
--- a/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx
+++ b/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx
@@ -26,7 +26,7 @@ export const WorkspaceSettingsSidebar = observer(() => {
return (
-
SETTINGS
+
{t("settings")}
{WORKSPACE_SETTINGS_LINKS.map(
(link) =>
diff --git a/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx b/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx
index 412c29f5dd2..0b300928c5c 100644
--- a/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx
+++ b/web/app/[workspaceSlug]/(projects)/settings/webhooks/page.tsx
@@ -38,7 +38,9 @@ const WebhooksListPage = observer(() => {
workspaceSlug && canPerformWorkspaceAdminActions ? () => fetchWebhooks(workspaceSlug.toString()) : null
);
- const pageTitle = currentWorkspace?.name ? `${currentWorkspace.name} - Webhooks` : undefined;
+ const pageTitle = currentWorkspace?.name
+ ? `${currentWorkspace.name} - ${t("workspace_settings.settings.webhooks.title")}`
+ : undefined;
// clear secret key when modal is closed.
useEffect(() => {
@@ -67,9 +69,9 @@ const WebhooksListPage = observer(() => {
{Object.keys(webhooks).length > 0 ? (
-
Webhooks
+
{t("workspace_settings.settings.webhooks.title")}
setShowCreateWebhookModal(true)}>
- Add webhook
+ {t("workspace_settings.settings.webhooks.add_webhook")}
@@ -77,9 +79,9 @@ const WebhooksListPage = observer(() => {
) : (
-
Webhooks
+
{t("workspace_settings.settings.webhooks.title")}
setShowCreateWebhookModal(true)}>
- Add webhook
+ {t("workspace_settings.settings.webhooks.add_webhook")}
diff --git a/web/ce/components/workspace/billing/root.tsx b/web/ce/components/workspace/billing/root.tsx
index 4acba0af06d..e9c6bd8f7c0 100644
--- a/web/ce/components/workspace/billing/root.tsx
+++ b/web/ce/components/workspace/billing/root.tsx
@@ -1,21 +1,27 @@
import { MARKETING_PRICING_PAGE_LINK } from "@plane/constants";
+import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/ui";
-export const BillingRoot = () => (
-
-
-
-
Billing and Plans
-
-
-
+export const BillingRoot = () => {
+ const { t } = useTranslation();
+ return (
+
-
Current plan
-
You are currently using the free plan
-
- View plans
-
+
+
{t("workspace_settings.settings.billing_and_plans.title")}
+
+
+
-
-
-);
+
+ );
+};
diff --git a/web/ce/components/workspace/delete-workspace-section.tsx b/web/ce/components/workspace/delete-workspace-section.tsx
index 93836284f8f..81fc754593f 100644
--- a/web/ce/components/workspace/delete-workspace-section.tsx
+++ b/web/ce/components/workspace/delete-workspace-section.tsx
@@ -2,6 +2,7 @@ import { FC, useState } from "react";
import { observer } from "mobx-react";
import { ChevronDown, ChevronUp } from "lucide-react";
// types
+import { useTranslation } from "@plane/i18n";
import { IWorkspace } from "@plane/types";
// ui
import { Button, Collapsible } from "@plane/ui";
@@ -17,6 +18,7 @@ export const DeleteWorkspaceSection: FC
= observer((props) =>
// states
const [isOpen, setIsOpen] = useState(false);
const [deleteWorkspaceModal, setDeleteWorkspaceModal] = useState(false);
+ const { t } = useTranslation();
return (
<>
@@ -34,19 +36,20 @@ export const DeleteWorkspaceSection: FC = observer((props) =>
buttonClassName="flex w-full items-center justify-between py-4"
title={
<>
- Delete workspace
+
+ {t("workspace_settings.settings.general.delete_workspace")}
+
{isOpen ? : }
>
}
>
- When deleting a workspace, all of the data and resources within that workspace will be permanently
- removed and cannot be recovered.
+ {t("workspace_settings.settings.general.delete_workspace_description")}
setDeleteWorkspaceModal(true)}>
- Delete my workspace
+ {t("workspace_settings.settings.general.delete_btn")}
diff --git a/web/ce/components/workspace/settings/useMemberColumns.tsx b/web/ce/components/workspace/settings/useMemberColumns.tsx
index 64c92cf52ab..f58a1ea9297 100644
--- a/web/ce/components/workspace/settings/useMemberColumns.tsx
+++ b/web/ce/components/workspace/settings/useMemberColumns.tsx
@@ -1,5 +1,6 @@
import { useState } from "react";
import { useParams } from "next/navigation";
+import { useTranslation } from "@plane/i18n";
import { AccountTypeColumn, NameColumn, RowData } from "@/components/workspace/settings/member-columns";
import { useUser, useUserPermissions } from "@/hooks/store";
import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions";
@@ -12,6 +13,7 @@ export const useMemberColumns = () => {
const { data: currentUser } = useUser();
const { allowPermissions } = useUserPermissions();
+ const { t } = useTranslation();
const getFormattedDate = (dateStr: string) => {
const date = new Date(dateStr);
@@ -26,7 +28,7 @@ export const useMemberColumns = () => {
const columns = [
{
key: "Full name",
- content: "Full name",
+ content: t("workspace_settings.settings.members.details.full_name"),
thClassName: "text-left",
tdRender: (rowData: RowData) => (
{
{
key: "Display name",
- content: "Display name",
+ content: t("workspace_settings.settings.members.details.display_name"),
tdRender: (rowData: RowData) => {rowData.member.display_name}
,
},
{
key: "Email address",
- content: "Email address",
+ content: t("workspace_settings.settings.members.details.email_address"),
tdRender: (rowData: RowData) => {rowData.member.email}
,
},
{
key: "Account type",
- content: "Account type",
+ content: t("workspace_settings.settings.members.details.account_type"),
tdRender: (rowData: RowData) => ,
},
{
key: "Authentication",
- content: "Authentication",
+ content: t("workspace_settings.settings.members.details.authentication"),
tdRender: (rowData: RowData) => (
{rowData.member.last_login_medium?.replace("-", " ")}
),
@@ -67,7 +69,7 @@ export const useMemberColumns = () => {
{
key: "Joining date",
- content: "Joining date",
+ content: t("workspace_settings.settings.members.details.joining_date"),
tdRender: (rowData: RowData) => {getFormattedDate(rowData?.member?.joining_date || "")}
,
},
];
diff --git a/web/core/components/api-token/modal/form.tsx b/web/core/components/api-token/modal/form.tsx
index 18ade7f2af7..17e14ae563c 100644
--- a/web/core/components/api-token/modal/form.tsx
+++ b/web/core/components/api-token/modal/form.tsx
@@ -5,6 +5,7 @@ import { add } from "date-fns";
import { Controller, useForm } from "react-hook-form";
import { Calendar } from "lucide-react";
// types
+import { useTranslation } from "@plane/i18n";
import { IApiToken } from "@plane/types";
// ui
import { Button, CustomSelect, Input, TextArea, ToggleSwitch, TOAST_TYPE, setToast } from "@plane/ui";
@@ -76,6 +77,8 @@ export const CreateApiTokenForm: React.FC = (props) => {
reset,
watch,
} = useForm({ defaultValues });
+ // hooks
+ const { t } = useTranslation();
const handleFormSubmit = async (data: IApiToken) => {
// if never expires is toggled off, and the user has not selected a custom date or a predefined date, show an error
@@ -115,19 +118,21 @@ export const CreateApiTokenForm: React.FC = (props) => {
return (
diff --git a/web/core/components/exporter/guide.tsx b/web/core/components/exporter/guide.tsx
index 828afab0c1c..7e53cf93c1e 100644
--- a/web/core/components/exporter/guide.tsx
+++ b/web/core/components/exporter/guide.tsx
@@ -140,7 +140,9 @@ const IntegrationGuide = observer(() => {
-
Previous exports
+
+ {t("workspace_settings.settings.exports.previous_exports")}
+
{
onClick={handleRefresh}
>
{" "}
- {refreshing ? "Refreshing..." : "Refresh status"}
+ {refreshing ? `${t("refreshing")}...` : t("refresh_status")}
@@ -162,7 +164,7 @@ const IntegrationGuide = observer(() => {
}`}
>
-
Prev
+
{t("prev")}
{
: "cursor-not-allowed opacity-75"
}`}
>
- Next
+ {t("next")}
diff --git a/web/core/components/web-hooks/create-webhook-modal.tsx b/web/core/components/web-hooks/create-webhook-modal.tsx
index 87a564cba4a..d5eecbe9c7a 100644
--- a/web/core/components/web-hooks/create-webhook-modal.tsx
+++ b/web/core/components/web-hooks/create-webhook-modal.tsx
@@ -3,6 +3,7 @@
import React, { useState } from "react";
import { useParams } from "next/navigation";
// types
+import { useTranslation } from "@plane/i18n";
import { IWebhook, IWorkspace, TWebhookEventTypes } from "@plane/types";
// ui
import { EModalPosition, EModalWidth, ModalCore, TOAST_TYPE, setToast } from "@plane/ui";
@@ -34,6 +35,7 @@ export const CreateWebhookModal: React.FC
= (props) => {
const [generatedWebhook, setGeneratedKey] = useState(null);
// router
const { workspaceSlug } = useParams();
+ const { t } = useTranslation();
const handleCreateWebhook = async (formData: IWebhook, webhookEventType: TWebhookEventTypes) => {
if (!workspaceSlug) return;
@@ -65,8 +67,8 @@ export const CreateWebhookModal: React.FC = (props) => {
.then(({ webHook, secretKey }) => {
setToast({
type: TOAST_TYPE.SUCCESS,
- title: "Success!",
- message: "Webhook created successfully.",
+ title: t("workspace_settings.settings.webhooks.toasts.created.title"),
+ message: t("workspace_settings.settings.webhooks.toasts.created.message"),
});
setGeneratedKey(webHook);
@@ -77,8 +79,8 @@ export const CreateWebhookModal: React.FC = (props) => {
.catch((error) => {
setToast({
type: TOAST_TYPE.ERROR,
- title: "Error!",
- message: error?.error ?? "Something went wrong. Please try again.",
+ title: t("workspace_settings.settings.webhooks.toasts.not_created.title"),
+ message: error?.error ?? t("workspace_settings.settings.webhooks.toasts.not_created.message"),
});
});
};
diff --git a/web/core/components/web-hooks/form/event-types.tsx b/web/core/components/web-hooks/form/event-types.tsx
index c90500a7405..dd69dbf8953 100644
--- a/web/core/components/web-hooks/form/event-types.tsx
+++ b/web/core/components/web-hooks/form/event-types.tsx
@@ -1,4 +1,5 @@
// types
+import { useTranslation } from "@plane/i18n";
import { TWebhookEventTypes } from "@plane/types";
type Props = {
@@ -19,10 +20,11 @@ const WEBHOOK_EVENT_TYPES: { key: TWebhookEventTypes; label: string }[] = [
export const WebhookOptions: React.FC = (props) => {
const { value, onChange } = props;
+ const { t } = useTranslation();
return (
<>
- Which events would you like to trigger this webhook?
+ {t("workspace_settings.settings.webhooks.modal.question")}
{WEBHOOK_EVENT_TYPES.map((option) => (
diff --git a/web/core/components/web-hooks/form/form.tsx b/web/core/components/web-hooks/form/form.tsx
index bbb953cb382..ba55a75b302 100644
--- a/web/core/components/web-hooks/form/form.tsx
+++ b/web/core/components/web-hooks/form/form.tsx
@@ -3,6 +3,7 @@
import React, { FC, useEffect, useState } from "react";
import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form";
+import { useTranslation } from "@plane/i18n";
import { IWebhook, TWebhookEventTypes } from "@plane/types";
// hooks
import { Button } from "@plane/ui";
@@ -39,6 +40,7 @@ export const WebhookForm: FC
= observer((props) => {
const [webhookEventType, setWebhookEventType] = useState("all");
// store hooks
const { webhookSecretKey } = useWebhook();
+ const { t } = useTranslation();
// use form
const {
handleSubmit,
@@ -62,14 +64,18 @@ export const WebhookForm: FC = observer((props) => {
return (