diff --git a/web/core/components/home/widgets/links/use-links.tsx b/web/core/components/home/widgets/links/use-links.tsx
index a6668d92efc..3607f5b6abf 100644
--- a/web/core/components/home/widgets/links/use-links.tsx
+++ b/web/core/components/home/widgets/links/use-links.tsx
@@ -1,4 +1,5 @@
import { useMemo } from "react";
+import { useTranslation } from "@plane/i18n";
import { TProjectLink } from "@plane/types";
import { setToast, TOAST_TYPE } from "@plane/ui";
import { useHome } from "@/hooks/store/use-home";
@@ -26,6 +27,7 @@ export const useLinks = (workspaceSlug: string) => {
fetchLinks,
},
} = useHome();
+ const { t } = useTranslation();
const linkOperations: TLinkOperations = useMemo(
() => ({
@@ -34,17 +36,17 @@ export const useLinks = (workspaceSlug: string) => {
if (!workspaceSlug) throw new Error("Missing required fields");
await createLink(workspaceSlug, data);
setToast({
- message: "The link has been successfully created",
+ message: t("home.quick_links.toasts.created.message"),
type: TOAST_TYPE.SUCCESS,
- title: "Link created",
+ title: t("home.quick_links.toasts.created.title"),
});
toggleLinkModal(false);
} catch (error: any) {
console.error("error", error);
setToast({
- message: error?.data?.error ?? "The link could not be created",
+ message: error?.data?.error ?? t("home.quick_links.toasts.not_created.message"),
type: TOAST_TYPE.ERROR,
- title: "Link not created",
+ title: t("home.quick_links.toasts.not_created.title"),
});
throw error;
}
@@ -54,16 +56,16 @@ export const useLinks = (workspaceSlug: string) => {
if (!workspaceSlug) throw new Error("Missing required fields");
await updateLink(workspaceSlug, linkId, data);
setToast({
- message: "The link has been successfully updated",
+ message: t("home.quick_links.toasts.updated.message"),
type: TOAST_TYPE.SUCCESS,
- title: "Link updated",
+ title: t("home.quick_links.toasts.updated.title"),
});
toggleLinkModal(false);
- } catch (error) {
+ } catch (error: any) {
setToast({
- message: "The link could not be updated",
+ message: error?.data?.error ?? t("home.quick_links.toasts.not_updated.message"),
type: TOAST_TYPE.ERROR,
- title: "Link not updated",
+ title: t("home.quick_links.toasts.not_updated.title"),
});
throw error;
}
@@ -73,15 +75,15 @@ export const useLinks = (workspaceSlug: string) => {
if (!workspaceSlug) throw new Error("Missing required fields");
await removeLink(workspaceSlug, linkId);
setToast({
- message: "The link has been successfully removed",
+ message: t("home.quick_links.toasts.removed.message"),
type: TOAST_TYPE.SUCCESS,
- title: "Link removed",
+ title: t("home.quick_links.toasts.removed.message"),
});
- } catch (error) {
+ } catch (error: any) {
setToast({
- message: "The link could not be removed",
+ message: error?.data?.error ?? t("home.quick_links.toasts.not_removed.message"),
type: TOAST_TYPE.ERROR,
- title: "Link not removed",
+ title: t("home.quick_links.toasts.not_removed.title"),
});
}
},
diff --git a/web/core/components/home/widgets/manage/index.tsx b/web/core/components/home/widgets/manage/index.tsx
index 9a2239e2ee9..8834ca69dcb 100644
--- a/web/core/components/home/widgets/manage/index.tsx
+++ b/web/core/components/home/widgets/manage/index.tsx
@@ -4,6 +4,7 @@ import { FC } from "react";
import { observer } from "mobx-react";
// plane types
// plane ui
+import { useTranslation } from "@plane/i18n";
import { EModalWidth, ModalCore } from "@plane/ui";
import { WidgetList } from "./widget-list";
@@ -16,11 +17,12 @@ export type TProps = {
export const ManageWidgetsModal: FC
= observer((props) => {
// props
const { workspaceSlug, isModalOpen, handleOnClose } = props;
+ const { t } = useTranslation();
return (
-
Manage widgets
+
{t("home.manage_widgets")}
diff --git a/web/core/components/home/widgets/manage/widget-item.tsx b/web/core/components/home/widgets/manage/widget-item.tsx
index bfd9ca38812..42cb7f5c0d4 100644
--- a/web/core/components/home/widgets/manage/widget-item.tsx
+++ b/web/core/components/home/widgets/manage/widget-item.tsx
@@ -15,6 +15,7 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { createRoot } from "react-dom/client";
// plane types
+import { useTranslation } from "@plane/i18n";
import { InstructionType, TWidgetEntityData } from "@plane/types";
// plane ui
import { DropIndicator, ToggleSwitch } from "@plane/ui";
@@ -44,6 +45,7 @@ export const WidgetItem: FC = observer((props) => {
const elementRef = useRef(null);
// hooks
const { widgetsMap } = useHome();
+ const { t } = useTranslation();
// derived values
const widget = widgetsMap[widgetId] as TWidgetEntityData;
const widgetTitle = HOME_WIDGETS_LIST[widget.key]?.title;
@@ -128,7 +130,7 @@ export const WidgetItem: FC = observer((props) => {
>
-
{widgetTitle}
+
{t(widgetTitle, { count: 1 })}
{
const { orderedWidgets, reorderWidget, toggleWidget } = useHome();
+ const { t } = useTranslation();
const handleDrop = (self: DropTargetRecord, source: ElementDragPayload, location: DragLocationHistory) => {
const dropTargets = location?.current?.dropTargets ?? [];
@@ -31,14 +33,14 @@ export const WidgetList = observer(({ workspaceSlug }: { workspaceSlug: string }
reorderWidget(workspaceSlug, sourceData.id, droppedId, instruction); /** sequence */
setToast({
type: TOAST_TYPE.SUCCESS,
- title: "Success!",
- message: "Widget reordered successfully.",
+ title: t("toast.success"),
+ message: t("home.widget.reordered_successfully"),
});
} catch {
setToast({
type: TOAST_TYPE.ERROR,
- title: "Error!",
- message: "Error occurred while reordering widget.",
+ title: t("toast.error"),
+ message: t("home.widget.reordering_failed"),
});
}
}
diff --git a/web/core/components/home/widgets/recents/filters.tsx b/web/core/components/home/widgets/recents/filters.tsx
index da7e9e39ab3..255249dd14e 100644
--- a/web/core/components/home/widgets/recents/filters.tsx
+++ b/web/core/components/home/widgets/recents/filters.tsx
@@ -3,6 +3,7 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { ChevronDown } from "lucide-react";
+import { useTranslation } from "@plane/i18n";
import { TRecentActivityFilterKeys } from "@plane/types";
import { CustomMenu } from "@plane/ui";
import { cn } from "@plane/utils";
@@ -11,11 +12,12 @@ export type TFiltersDropdown = {
className?: string;
activeFilter: TRecentActivityFilterKeys;
setActiveFilter: (filter: TRecentActivityFilterKeys) => void;
- filters: { name: TRecentActivityFilterKeys; icon?: React.ReactNode }[];
+ filters: { name: TRecentActivityFilterKeys; icon?: React.ReactNode; i18n_key: string }[];
};
export const FiltersDropdown: FC = observer((props) => {
const { className, activeFilter, setActiveFilter, filters } = props;
+ const { t } = useTranslation();
const DropdownOptions = () =>
filters?.map((filter) => (
@@ -27,10 +29,11 @@ export const FiltersDropdown: FC = observer((props) => {
}}
>
{filter.icon && {filter.icon}
}
- {`${filter.name}s`}
+ {t(filter.i18n_key)}
));
+ const title = activeFilter ? filters?.find((filter) => filter.name === activeFilter)?.i18n_key : "";
return (
= observer((props) => {
placement="bottom-start"
customButton={
- {activeFilter && `${activeFilter}s`}
+ {t(title || "")}
}
diff --git a/web/core/components/home/widgets/recents/index.tsx b/web/core/components/home/widgets/recents/index.tsx
index 8530563de34..e23c11c54e2 100644
--- a/web/core/components/home/widgets/recents/index.tsx
+++ b/web/core/components/home/widgets/recents/index.tsx
@@ -5,6 +5,7 @@ import { observer } from "mobx-react";
// types
import useSWR from "swr";
import { Briefcase, FileText } from "lucide-react";
+import { useTranslation } from "@plane/i18n";
import { TActivityEntityData, THomeWidgetProps, TRecentActivityFilterKeys } from "@plane/types";
// components
import { LayersIcon } from "@plane/ui";
@@ -20,11 +21,11 @@ import { RecentProject } from "./project";
const WIDGET_KEY = EWidgetKeys.RECENT_ACTIVITY;
const workspaceService = new WorkspaceService();
-const filters: { name: TRecentActivityFilterKeys; icon?: React.ReactNode }[] = [
- { name: "all item" },
- { name: "issue", icon: },
- { name: "page", icon: },
- { name: "project", icon: },
+const filters: { name: TRecentActivityFilterKeys; icon?: React.ReactNode; i18n_key: string }[] = [
+ { name: "all item", i18n_key: "home.recents.filters.all" },
+ { name: "issue", icon: , i18n_key: "home.recents.filters.issues" },
+ { name: "page", icon: , i18n_key: "home.recents.filters.pages" },
+ { name: "project", icon: , i18n_key: "home.recents.filters.projects" },
];
type TRecentWidgetProps = THomeWidgetProps & {
@@ -40,6 +41,7 @@ export const RecentActivityWidget: React.FC = observer((prop
const ref = useRef(null);
// store hooks
const { joinedProjectIds, loader } = useProject();
+ const { t } = useTranslation();
const { data: recents, isLoading } = useSWR(
workspaceSlug ? `WORKSPACE_RECENT_ACTIVITY_${workspaceSlug}_${filter}` : null,
@@ -77,7 +79,7 @@ export const RecentActivityWidget: React.FC = observer((prop
return (
-
Recents
+
{t("home.recents.title")}
{showFilterSelect &&
}
@@ -94,7 +96,7 @@ export const RecentActivityWidget: React.FC
= observer((prop
buttonClassName="bg-custom-background-90/20"
>
-
Recents
+
{t("home.recents.title")}
{showFilterSelect &&
}
diff --git a/web/core/components/stickies/delete-modal.tsx b/web/core/components/stickies/delete-modal.tsx
index c810f426841..ecbceae93f3 100644
--- a/web/core/components/stickies/delete-modal.tsx
+++ b/web/core/components/stickies/delete-modal.tsx
@@ -3,6 +3,7 @@
import { useState } from "react";
import { observer } from "mobx-react";
// ui
+import { useTranslation } from "@plane/i18n";
import { AlertModalCore, TOAST_TYPE, setToast } from "@plane/ui";
interface IStickyDelete {
@@ -15,6 +16,8 @@ export const StickyDeleteModal: React.FC
= observer((props) => {
const { isOpen, handleClose, handleSubmit } = props;
// states
const [loader, setLoader] = useState(false);
+ // hooks
+ const { t } = useTranslation();
const formSubmit = async () => {
try {
@@ -23,8 +26,8 @@ export const StickyDeleteModal: React.FC = observer((props) => {
} catch {
setToast({
type: TOAST_TYPE.ERROR,
- title: "Warning!",
- message: "Something went wrong. Please try again later.",
+ title: t("stickies.toasts.not_removed.title"),
+ message: t("stickies.toasts.not_removed.message"),
});
} finally {
setLoader(false);
@@ -37,8 +40,8 @@ export const StickyDeleteModal: React.FC = observer((props) => {
handleSubmit={formSubmit}
isSubmitting={loader}
isOpen={isOpen}
- title="Delete sticky"
- content="Are you sure you want to delete the sticky?"
+ title={t("stickies.delete")}
+ content={t("stickies.delete_confirmation")}
/>
);
});
diff --git a/web/core/components/stickies/layout/stickies-truncated.tsx b/web/core/components/stickies/layout/stickies-truncated.tsx
index c7af1191b8f..c163d7d3223 100644
--- a/web/core/components/stickies/layout/stickies-truncated.tsx
+++ b/web/core/components/stickies/layout/stickies-truncated.tsx
@@ -3,6 +3,7 @@ import Link from "next/link";
import { useParams } from "next/navigation";
import useSWR from "swr";
// plane utils
+import { useTranslation } from "@plane/i18n";
import { cn } from "@plane/utils";
// hooks
import { useSticky } from "@/hooks/use-stickies";
@@ -20,6 +21,7 @@ export const StickiesTruncated = observer((props: StickiesTruncatedProps) => {
const { workspaceSlug } = useParams();
// store hooks
const { fetchWorkspaceStickies } = useSticky();
+ const { t } = useTranslation();
useSWR(
workspaceSlug ? `WORKSPACE_STICKIES_${workspaceSlug}` : null,
@@ -40,7 +42,7 @@ export const StickiesTruncated = observer((props: StickiesTruncatedProps) => {
)}
onClick={handleClose}
>
- Show all
+ {t("show_all")}
}
>
diff --git a/web/core/components/stickies/modal/search.tsx b/web/core/components/stickies/modal/search.tsx
index 15e21c81126..22499c03a8b 100644
--- a/web/core/components/stickies/modal/search.tsx
+++ b/web/core/components/stickies/modal/search.tsx
@@ -8,6 +8,7 @@ import { Search, X } from "lucide-react";
// plane hooks
import { useOutsideClickDetector } from "@plane/hooks";
// helpers
+import { useTranslation } from "@plane/i18n";
import { cn } from "@/helpers/common.helper";
import { useSticky } from "@/hooks/use-stickies";
@@ -16,6 +17,7 @@ export const StickySearch: FC = observer(() => {
const { workspaceSlug } = useParams();
// hooks
const { searchQuery, updateSearchQuery, fetchWorkspaceStickies } = useSticky();
+ const { t } = useTranslation();
// refs
const inputRef = useRef(null);
// states
@@ -71,7 +73,7 @@ export const StickySearch: FC = observer(() => {
{
updateSearchQuery(e.target.value);
diff --git a/web/core/components/stickies/sticky/use-operations.tsx b/web/core/components/stickies/sticky/use-operations.tsx
index 73f21231857..b582fd5638c 100644
--- a/web/core/components/stickies/sticky/use-operations.tsx
+++ b/web/core/components/stickies/sticky/use-operations.tsx
@@ -1,5 +1,6 @@
import { useMemo } from "react";
// plane types
+import { useTranslation } from "@plane/i18n";
import { InstructionType, TSticky } from "@plane/types";
// plane ui
import { setToast, TOAST_TYPE } from "@plane/ui";
@@ -36,13 +37,14 @@ export const useStickyOperations = (props: TProps) => {
// store hooks
const { stickies, getWorkspaceStickyIds, createSticky, updateSticky, deleteSticky, updateStickyPosition } =
useSticky();
+ const { t } = useTranslation();
const isValid = (data: Partial) => {
if (data.name && data.name.length > 100) {
setToast({
type: TOAST_TYPE.ERROR,
- title: "Sticky not updated",
- message: "The sticky name cannot be longer than 100 characters.",
+ title: t("stickies.toasts.not_updated.title"),
+ message: t("stickies.toasts.errors.wrong_name"),
});
return false;
}
@@ -63,9 +65,9 @@ export const useStickyOperations = (props: TProps) => {
const latestSticky = stickies[workspaceStickIds[0]];
if (latestSticky && (!latestSticky.description_html || isCommentEmpty(latestSticky.description_html))) {
setToast({
- message: "There already exists a sticky with no description",
+ message: t("stickies.toasts.errors.already_exists"),
type: TOAST_TYPE.WARNING,
- title: "Sticky already created",
+ title: t("stickies.toasts.not_created.title"),
});
return;
}
@@ -75,15 +77,15 @@ export const useStickyOperations = (props: TProps) => {
await createSticky(workspaceSlug, payload);
setToast({
type: TOAST_TYPE.SUCCESS,
- title: "Sticky created",
- message: "The sticky has been successfully created.",
+ title: t("stickies.toasts.created.title"),
+ message: t("stickies.toasts.created.message"),
});
} catch (error: any) {
console.error("Error in creating sticky:", error);
setToast({
type: TOAST_TYPE.ERROR,
- title: "Sticky not created",
- message: error?.data?.error ?? "The sticky could not be created.",
+ title: t("stickies.toasts.not_created.title"),
+ message: error?.data?.error ?? t("stickies.toasts.not_created.message"),
});
}
},
@@ -96,8 +98,8 @@ export const useStickyOperations = (props: TProps) => {
console.error("Error in updating sticky:", error);
setToast({
type: TOAST_TYPE.ERROR,
- title: "Sticky not updated",
- message: "The sticky could not be updated.",
+ title: t("stickies.toasts.not_updated.title"),
+ message: t("stickies.toasts.not_updated.message"),
});
}
},
@@ -107,15 +109,15 @@ export const useStickyOperations = (props: TProps) => {
await deleteSticky(workspaceSlug, stickyId);
setToast({
type: TOAST_TYPE.SUCCESS,
- title: "Sticky removed",
- message: "The sticky has been removed successfully.",
+ title: t("stickies.toasts.removed.title"),
+ message: t("stickies.toasts.removed.message"),
});
} catch (error) {
console.error("Error in removing sticky:", error);
setToast({
type: TOAST_TYPE.ERROR,
- title: "Sticky not removed",
- message: "The sticky could not be removed.",
+ title: t("stickies.toasts.not_removed.title"),
+ message: t("stickies.toasts.not_removed.message"),
});
}
},
@@ -132,8 +134,8 @@ export const useStickyOperations = (props: TProps) => {
console.error("Error in updating sticky position:", error);
setToast({
type: TOAST_TYPE.ERROR,
- title: "Sticky not updated",
- message: "The sticky could not be updated.",
+ title: t("stickies.toasts.not_updated.title"),
+ message: t("stickies.toasts.not_updated.message"),
});
}
},
diff --git a/web/core/components/stickies/widget.tsx b/web/core/components/stickies/widget.tsx
index cafec4013ab..e94741cc096 100644
--- a/web/core/components/stickies/widget.tsx
+++ b/web/core/components/stickies/widget.tsx
@@ -2,6 +2,7 @@ import { observer } from "mobx-react";
import { useParams } from "next/navigation";
import { Plus } from "lucide-react";
// hooks
+import { useTranslation } from "@plane/i18n";
import { useSticky } from "@/hooks/use-stickies";
import { StickiesTruncated } from "./layout";
import { StickySearch } from "./modal/search";
@@ -12,6 +13,7 @@ export const StickiesWidget: React.FC = observer(() => {
const { workspaceSlug } = useParams();
// store hooks
const { creatingSticky, toggleShowNewSticky } = useSticky();
+ const { t } = useTranslation();
// sticky operations
const { stickyOperations } = useStickyOperations({
workspaceSlug: workspaceSlug?.toString() ?? "",
@@ -20,7 +22,7 @@ export const StickiesWidget: React.FC = observer(() => {
return (
-
Your stickies
+
{t("stickies.title")}
{/* actions */}
@@ -33,7 +35,7 @@ export const StickiesWidget: React.FC = observer(() => {
disabled={creatingSticky}
>
-
Add sticky
+
{t("stickies.add")}
{creatingSticky && (
{
const SIDEBAR_USER_MENU_ITEMS = [
{
key: "home",
- labelTranslationKey: "home",
+ labelTranslationKey: "home.title",
href: `/${workspaceSlug.toString()}/`,
access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.GUEST],
Icon: Home,