diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts index 2b3964ae9fd..673a76e7b6f 100644 --- a/packages/constants/src/index.ts +++ b/packages/constants/src/index.ts @@ -14,3 +14,4 @@ export * from "./swr"; export * from "./user"; export * from "./workspace"; export * from "./stickies"; +export * from "./profile"; diff --git a/web/core/constants/profile.ts b/packages/constants/src/profile.ts similarity index 69% rename from web/core/constants/profile.ts rename to packages/constants/src/profile.ts index 14fc08638de..f7765a0cfc0 100644 --- a/web/core/constants/profile.ts +++ b/packages/constants/src/profile.ts @@ -1,48 +1,38 @@ -import React from "react"; -// icons -import { Activity, Bell, CircleUser, KeyRound, LucideProps, Settings2 } from "lucide-react"; - export const PROFILE_ACTION_LINKS: { key: string; - label: string; + i18n_label: string; href: string; highlight: (pathname: string) => boolean; - Icon: React.FC; }[] = [ { - key: "profile.label", - label: "Profile", + key: "profile", + i18n_label: "profile.actions.profile", href: `/profile`, highlight: (pathname: string) => pathname === "/profile/", - Icon: CircleUser, }, { key: "security", - label: "Security", + i18n_label: "profile.actions.security", href: `/profile/security`, highlight: (pathname: string) => pathname === "/profile/security/", - Icon: KeyRound, }, { key: "activity", - label: "Activity", + i18n_label: "profile.actions.activity", href: `/profile/activity`, highlight: (pathname: string) => pathname === "/profile/activity/", - Icon: Activity, }, { key: "appearance", - label: "Appearance", + i18n_label: "profile.actions.appearance", href: `/profile/appearance`, highlight: (pathname: string) => pathname.includes("/profile/appearance"), - Icon: Settings2, }, { key: "notifications", - label: "Notifications", + i18n_label: "profile.actions.notifications", href: `/profile/notifications`, highlight: (pathname: string) => pathname === "/profile/notifications/", - Icon: Bell, }, ]; @@ -50,7 +40,7 @@ export const PROFILE_VIEWER_TAB = [ { key: "summary", route: "", - label: "Summary", + i18n_label: "profile.tabs.summary", selected: "/", }, ]; @@ -59,24 +49,25 @@ export const PROFILE_ADMINS_TAB = [ { key: "assigned", route: "assigned", - label: "Assigned", + i18n_label: "profile.tabs.assigned", selected: "/assigned/", }, { + key: "created", route: "created", - label: "Created", + i18n_label: "profile.tabs.created", selected: "/created/", }, { key: "subscribed", route: "subscribed", - label: "Subscribed", + i18n_label: "profile.tabs.subscribed", selected: "/subscribed/", }, { key: "activity", route: "activity", - label: "Activity", + i18n_label: "profile.tabs.activity", selected: "/activity/", }, ]; diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index d52d125529b..276384a0b4b 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -314,6 +314,7 @@ "remove_parent_issue": "Remove parent issue", "add_parent": "Add parent", "loading_members": "Loading members...", + "no_data_yet": "No Data yet", "connections": "Connections", "workspace_dashboard": { @@ -437,6 +438,45 @@ "profile": { "label": "Profile", + "page_label": "Your work", + "work": "Work", + "details": { + "joined_on": "Joined on", + "time_zone": "Timezone" + }, + "stats": { + "workload": "Workload", + "overview": "Overview", + "created": "Issues created", + "assigned": "Issues assigned", + "subscribed": "Issues subscribed", + "state_distribution": { + "title": "Issues by state", + "empty": "Create issues to view the them by states in the graph for better analysis." + }, + "priority_distribution": { + "title": "Issues by Priority", + "empty": "Create issues to view the them by priority in the graph for better analysis." + }, + "recent_activity": { + "title": "Recent activity", + "empty": "We couldn't find data. Kindly view your inputs" + } + }, + "actions": { + "profile": "Profile", + "security": "Security", + "activity": "Activity", + "appearance": "Appearance", + "notifications": "Notifications" + }, + "tabs": { + "summary": "Summary", + "assigned": "Assigned", + "created": "Created", + "subscribed": "Subscribed", + "activity": "Activity" + }, "empty_state": { "activity": { "title": "No activities yet", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index f516cf152d6..5fe8916cb5c 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -313,6 +313,8 @@ "remove_parent_issue": "Eliminar problema padre", "add_parent": "Agregar padre", "loading_members": "Cargando miembros...", + "inbox": "bandeja de entrada", + "no_data_yet": "Sin datos aún", "connections": "Conexiones", "workspace_dashboard": { @@ -436,6 +438,45 @@ "profile": { "label": "Perfil", + "page_label": "Tu trabajo", + "work": "Trabajo", + "details": { + "joined_on": "Se unió el", + "time_zone": "Zona horaria" + }, + "stats": { + "workload": "Carga de trabajo", + "overview": "Resumen", + "created": "Problemas creados", + "assigned": "Problemas asignados", + "subscribed": "Problemas suscritos", + "state_distribution": { + "title": "Problemas por estado", + "empty": "Crea problemas para verlos por estados en el gráfico para un mejor análisis." + }, + "priority_distribution": { + "title": "Problemas por prioridad", + "empty": "Crea problemas para verlos por prioridad en el gráfico para un mejor análisis." + }, + "recent_activity": { + "title": "Actividad reciente", + "empty": "No pudimos encontrar datos. Por favor revisa tus entradas" + } + }, + "actions": { + "profile": "Perfil", + "security": "Seguridad", + "activity": "Actividad", + "appearance": "Apariencia", + "notifications": "Notificaciones" + }, + "tabs": { + "summary": "Resumen", + "assigned": "Asignados", + "created": "Creados", + "subscribed": "Suscritos", + "activity": "Actividad" + }, "empty_state": { "activity": { "title": "Aún no hay actividades", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 4d5d7512efd..e4490819d4a 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -314,6 +314,8 @@ "remove_parent_issue": "Supprimer le problème parent", "add_parent": "Ajouter un parent", "loading_members": "Chargement des membres...", + "inbox": "Boîte de réception", + "no_data_yet": "Pas encore de données", "connections": "Connexions", "workspace_dashboard": { @@ -437,6 +439,45 @@ "profile": { "label": "Profil", + "page_label": "Votre travail", + "work": "Travail", + "details": { + "joined_on": "Inscrit le", + "time_zone": "Fuseau horaire" + }, + "stats": { + "workload": "Charge de travail", + "overview": "Aperçu", + "created": "Problèmes créés", + "assigned": "Problèmes assignés", + "subscribed": "Problèmes suivis", + "state_distribution": { + "title": "Problèmes par état", + "empty": "Créez des problèmes pour les visualiser par état dans le graphique pour une meilleure analyse." + }, + "priority_distribution": { + "title": "Problèmes par priorité", + "empty": "Créez des problèmes pour les visualiser par priorité dans le graphique pour une meilleure analyse." + }, + "recent_activity": { + "title": "Activité récente", + "empty": "Nous n'avons pas trouvé de données. Veuillez consulter vos entrées" + } + }, + "actions": { + "profile": "Profil", + "security": "Sécurité", + "activity": "Activité", + "appearance": "Apparence", + "notifications": "Notifications" + }, + "tabs": { + "summary": "Résumé", + "assigned": "Assignés", + "created": "Créés", + "subscribed": "Suivis", + "activity": "Activité" + }, "empty_state": { "activity": { "title": "Aucune activité pour le moment", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index d7c8e76322d..361cda4753a 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -314,14 +314,15 @@ "remove_parent_issue": "親問題を削除", "add_parent": "親問題を追加", "loading_members": "メンバーを読み込んでいます...", + "no_data_yet": "まだデータがありません", "connections": "接続", "workspace_dashboard": { - "empty_state": { - "general": { - "title": "プロジェクト、アクティビティ、指標の概要", - "description": "Planeへようこそ!私たちはあなたを迎えることができて嬉しいです。最初のプロジェクトを作成してタスクを追跡し、このページが進捗を助けるスペースに変わります。管理者は、チームを前進させるための要素も見ることができます。", - "primary_button": { + "empty_state": { + "general": { + "title": "プロジェクト、アクティビティ、指標の概要", + "description": "Planeへようこそ!私たちはあなたを迎えることができて嬉しいです。最初のプロジェクトを作成してタスクを追跡し、このページが進捗を助けるスペースに変わります。管理者は、チームを前進させるための要素も見ることができます。", + "primary_button": { "text": "最初のプロジェクトを作成", "comic": { "title": "すべてはPlaneでのプロジェクトから始まります", @@ -437,6 +438,45 @@ "profile": { "label": "プロフィール", + "page_label": "あなたの作業", + "work": "作業", + "details": { + "joined_on": "参加日", + "time_zone": "タイムゾーン" + }, + "stats": { + "workload": "作業負荷", + "overview": "概要", + "created": "作成した課題", + "assigned": "割り当てられた課題", + "subscribed": "購読中の課題", + "state_distribution": { + "title": "状態別の課題", + "empty": "より良い分析のために、グラフで状態別に表示する課題を作成してください。" + }, + "priority_distribution": { + "title": "優先度別の課題", + "empty": "より良い分析のために、グラフで優先度別に表示する課題を作成してください。" + }, + "recent_activity": { + "title": "最近の活動", + "empty": "データが見つかりませんでした。入力内容を確認してください" + } + }, + "actions": { + "profile": "プロフィール", + "security": "セキュリティ", + "activity": "アクティビティ", + "appearance": "外観", + "notifications": "通知" + }, + "tabs": { + "summary": "サマリー", + "assigned": "割り当て済み", + "created": "作成済み", + "subscribed": "購読中", + "activity": "アクティビティ" + }, "empty_state": { "activity": { "title": "まだアクティビティがありません", diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index 093027c16b1..0da2835d89f 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -315,5 +315,47 @@ "remove_parent_issue": "移除父问题", "add_parent": "添加父问题", "loading_members": "正在加载成员...", - "inbox": "收件箱" + "inbox": "收件箱", + "no_data_yet": "暂无数据", + "user_profile": { + "title": "你的工作", + "work": "工作", + "details": { + "joined_on": "加入时间", + "time_zone": "时区" + }, + "stats": { + "workload": "工作量", + "overview": "概述", + "created": "已创建问题", + "assigned": "已分配问题", + "subscribed": "已订阅问题", + "state_distribution": { + "title": "按状态显示的问题", + "empty": "创建问题以在图表中按状态查看它们,以便更好地分析。" + }, + "priority_distribution": { + "title": "按优先级显示的问题", + "empty": "创建问题以在图表中按优先级查看它们,以便更好地分析。" + }, + "recent_activity": { + "title": "最近活动", + "empty": "我们找不到数据。请查看您的输入" + } + }, + "actions": { + "profile": "个人资料", + "security": "安全", + "activity": "活动", + "appearance": "外观", + "notifications": "通知" + }, + "tabs": { + "summary": "摘要", + "assigned": "已分配", + "created": "已创建", + "subscribed": "已订阅", + "activity": "活动" + } + } } diff --git a/web/app/[workspaceSlug]/(projects)/profile/[userId]/header.tsx b/web/app/[workspaceSlug]/(projects)/profile/[userId]/header.tsx index 13a944c8819..fdffd0a0864 100644 --- a/web/app/[workspaceSlug]/(projects)/profile/[userId]/header.tsx +++ b/web/app/[workspaceSlug]/(projects)/profile/[userId]/header.tsx @@ -6,12 +6,13 @@ import { observer } from "mobx-react"; import Link from "next/link"; import { useParams } from "next/navigation"; import { ChevronDown, PanelRight } from "lucide-react"; +import { PROFILE_VIEWER_TAB, PROFILE_ADMINS_TAB } from "@plane/constants"; +import { useTranslation } from "@plane/i18n"; import { IUserProfileProjectSegregation } from "@plane/types"; import { Breadcrumbs, Header, CustomMenu, UserActivityIcon } from "@plane/ui"; import { BreadcrumbLink } from "@/components/common"; // components import { ProfileIssuesFilter } from "@/components/profile"; -import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile"; import { cn } from "@/helpers/common.helper"; import { useAppTheme, useUser, useUserPermissions } from "@/hooks/store"; import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/user-permissions"; @@ -30,6 +31,7 @@ export const UserProfileHeader: FC = observer((props) => { const { toggleProfileSidebar, profileSidebarCollapsed } = useAppTheme(); const { data: currentUser } = useUser(); const { workspaceUserInfo, allowPermissions } = useUserPermissions(); + const { t } = useTranslation(); // derived values const isAuthorized = allowPermissions( [EUserPermissions.ADMIN, EUserPermissions.MEMBER], @@ -44,7 +46,7 @@ export const UserProfileHeader: FC = observer((props) => { const isCurrentUser = currentUser?.id === userId; - const breadcrumbLabel = `${isCurrentUser ? "Your" : userName} Work`; + const breadcrumbLabel = isCurrentUser ? t("profile.page_label") : `${userName} ${t("profile.work")}`; return (
@@ -86,7 +88,7 @@ export const UserProfileHeader: FC = observer((props) => { href={`/${workspaceSlug}/profile/${userId}/${tab.route}`} className="w-full text-custom-text-300" > - {tab.label} + {t(tab.i18n_label)} ))} diff --git a/web/app/[workspaceSlug]/(projects)/profile/[userId]/layout.tsx b/web/app/[workspaceSlug]/(projects)/profile/[userId]/layout.tsx index d6743e8f2ba..3209586d4db 100644 --- a/web/app/[workspaceSlug]/(projects)/profile/[userId]/layout.tsx +++ b/web/app/[workspaceSlug]/(projects)/profile/[userId]/layout.tsx @@ -4,12 +4,12 @@ import { observer } from "mobx-react"; import { useParams, usePathname } from "next/navigation"; import useSWR from "swr"; // components +import { PROFILE_VIEWER_TAB, PROFILE_ADMINS_TAB } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { AppHeader, ContentWrapper } from "@/components/core"; import { ProfileSidebar } from "@/components/profile"; // constants import { USER_PROFILE_PROJECT_SEGREGATION } from "@/constants/fetch-keys"; -import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile"; // hooks import { useUserPermissions } from "@/hooks/store"; import useSize from "@/hooks/use-window-size"; @@ -66,7 +66,7 @@ const UseProfileLayout: React.FC = observer((props) => { diff --git a/web/app/[workspaceSlug]/(projects)/profile/[userId]/navbar.tsx b/web/app/[workspaceSlug]/(projects)/profile/[userId]/navbar.tsx index e002f8f6641..a91836518a7 100644 --- a/web/app/[workspaceSlug]/(projects)/profile/[userId]/navbar.tsx +++ b/web/app/[workspaceSlug]/(projects)/profile/[userId]/navbar.tsx @@ -2,12 +2,12 @@ import React from "react"; import Link from "next/link"; import { useParams, usePathname } from "next/navigation"; +import { PROFILE_VIEWER_TAB, PROFILE_ADMINS_TAB } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; // components // constants import { Header, EHeaderVariant } from "@plane/ui"; -import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile"; type Props = { isAuthorized: boolean; @@ -33,7 +33,7 @@ export const ProfileNavbar: React.FC = (props) => { : "border-transparent" }`} > - {t(tab.label)} + {t(tab.i18n_label)} ))} diff --git a/web/app/[workspaceSlug]/(projects)/profile/[userId]/page.tsx b/web/app/[workspaceSlug]/(projects)/profile/[userId]/page.tsx index 480e30aed37..aaacff0d7ed 100644 --- a/web/app/[workspaceSlug]/(projects)/profile/[userId]/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/profile/[userId]/page.tsx @@ -3,6 +3,7 @@ import { useParams } from "next/navigation"; import useSWR from "swr"; // types +import { useTranslation } from "@plane/i18n"; import { IUserStateDistribution, TStateGroups } from "@plane/types"; // components import { ContentWrapper } from "@plane/ui"; @@ -26,6 +27,7 @@ const userService = new UserService(); export default function ProfileOverviewPage() { const { workspaceSlug, userId } = useParams(); + const { t } = useTranslation(); const { data: userProfile } = useSWR( workspaceSlug && userId ? USER_PROFILE_DATA(workspaceSlug.toString(), userId.toString()) : null, workspaceSlug && userId ? () => userService.getUserProfileData(workspaceSlug.toString(), userId.toString()) : null @@ -40,7 +42,7 @@ export default function ProfileOverviewPage() { return ( <> - + diff --git a/web/app/profile/sidebar.tsx b/web/app/profile/sidebar.tsx index d3b98642161..77fdfb25448 100644 --- a/web/app/profile/sidebar.tsx +++ b/web/app/profile/sidebar.tsx @@ -5,15 +5,26 @@ import { observer } from "mobx-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; // icons -import { ChevronLeft, LogOut, MoveLeft, Plus, UserPlus } from "lucide-react"; +import { + ChevronLeft, + LogOut, + MoveLeft, + Plus, + UserPlus, + Activity, + Bell, + CircleUser, + KeyRound, + Settings2, +} from "lucide-react"; // plane imports +import { PROFILE_ACTION_LINKS } from "@plane/constants"; import { useOutsideClickDetector } from "@plane/hooks"; import { useTranslation } from "@plane/i18n"; import { TOAST_TYPE, Tooltip, setToast } from "@plane/ui"; // components import { SidebarNavItem } from "@/components/sidebar"; // constants -import { PROFILE_ACTION_LINKS } from "@/constants/profile"; // helpers import { cn } from "@/helpers/common.helper"; import { getFileURL } from "@/helpers/file.helper"; @@ -36,6 +47,19 @@ const WORKSPACE_ACTION_LINKS = [ }, ]; +export const ProjectActionIcons = ({ type, size, className }: { type: string; size?: number; className?: string }) => { + const icons = { + profile: CircleUser, + security: KeyRound, + activity: Activity, + appearance: Settings2, + notifications: Bell, + }; + + if (type === undefined) return null; + const Icon = icons[type as keyof typeof icons]; + return ; +}; export const ProfileLayoutSidebar = observer(() => { // states const [isSigningOut, setIsSigningOut] = useState(false); @@ -145,7 +169,8 @@ export const ProfileLayoutSidebar = observer(() => { isActive={link.highlight(pathname)} >
- + + {!sidebarCollapsed &&

{t(link.key)}

}
diff --git a/web/core/components/profile/overview/activity.tsx b/web/core/components/profile/overview/activity.tsx index 7e5e6062132..9ac14b2aafd 100644 --- a/web/core/components/profile/overview/activity.tsx +++ b/web/core/components/profile/overview/activity.tsx @@ -4,6 +4,7 @@ import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; // ui +import { useTranslation } from "@plane/i18n"; import { Loader, Card } from "@plane/ui"; // components import { ActivityMessage, IssueLink } from "@/components/core"; @@ -26,6 +27,7 @@ export const ProfileActivity = observer(() => { const { workspaceSlug, userId } = useParams(); // store hooks const { data: currentUser } = useUser(); + const { t } = useTranslation(); const { data: userProfileActivity } = useSWR( workspaceSlug && userId ? USER_PROFILE_ACTIVITY(workspaceSlug.toString(), userId.toString(), {}) : null, @@ -39,7 +41,7 @@ export const ProfileActivity = observer(() => { return (
-

Recent activity

+

{t("profile.stats.recent_activity.title")}

{userProfileActivity ? ( userProfileActivity.results.length > 0 ? ( @@ -81,8 +83,8 @@ export const ProfileActivity = observer(() => {
) : ( ) diff --git a/web/core/components/profile/overview/priority-distribution.tsx b/web/core/components/profile/overview/priority-distribution.tsx index 66f0e02e718..856f7259157 100644 --- a/web/core/components/profile/overview/priority-distribution.tsx +++ b/web/core/components/profile/overview/priority-distribution.tsx @@ -1,6 +1,7 @@ "use client"; // ui +import { useTranslation } from "@plane/i18n"; import { IUserProfileData } from "@plane/types"; import { Loader, Card } from "@plane/ui"; import { BarGraph, ProfileEmptyState } from "@/components/ui"; @@ -14,77 +15,80 @@ type Props = { userProfile: IUserProfileData | undefined; }; -export const ProfilePriorityDistribution: React.FC = ({ userProfile }) => ( -
-

Issues by Priority

- {userProfile ? ( - - {userProfile.priority_distribution.length > 0 ? ( - ({ - priority: capitalizeFirstLetter(priority.priority ?? "None"), - value: priority.priority_count, - }))} - height="300px" - indexBy="priority" - keys={["value"]} - borderRadius={4} - padding={0.7} - customYAxisTickValues={userProfile.priority_distribution.map((p) => p.priority_count)} - tooltip={(datum) => ( -
- - {datum.data.priority}: - {datum.value} -
- )} - colors={(datum) => { - if (datum.data.priority === "Urgent") return "#991b1b"; - else if (datum.data.priority === "High") return "#ef4444"; - else if (datum.data.priority === "Medium") return "#f59e0b"; - else if (datum.data.priority === "Low") return "#16a34a"; - else return "#e5e5e5"; - }} - theme={{ - axis: { - domain: { +export const ProfilePriorityDistribution: React.FC = ({ userProfile }) => { + const { t } = useTranslation(); + return ( +
+

{t("profile.stats.priority_distribution.title")}

+ {userProfile ? ( + + {userProfile.priority_distribution.length > 0 ? ( + ({ + priority: capitalizeFirstLetter(priority.priority ?? "None"), + value: priority.priority_count, + }))} + height="300px" + indexBy="priority" + keys={["value"]} + borderRadius={4} + padding={0.7} + customYAxisTickValues={userProfile.priority_distribution.map((p) => p.priority_count)} + tooltip={(datum) => ( +
+ + {datum.data.priority}: + {datum.value} +
+ )} + colors={(datum) => { + if (datum.data.priority === "Urgent") return "#991b1b"; + else if (datum.data.priority === "High") return "#ef4444"; + else if (datum.data.priority === "Medium") return "#f59e0b"; + else if (datum.data.priority === "Low") return "#16a34a"; + else return "#e5e5e5"; + }} + theme={{ + axis: { + domain: { + line: { + stroke: "transparent", + }, + }, + }, + grid: { line: { stroke: "transparent", }, }, - }, - grid: { - line: { - stroke: "transparent", - }, - }, - }} - /> - ) : ( -
- -
- )} -
- ) : ( -
- - - - - - - -
- )} -
-); + ) : ( +
+ +
+ )} +
+ ) : ( +
+ + + + + + + +
+ )} +
+ ); +}; diff --git a/web/core/components/profile/overview/state-distribution.tsx b/web/core/components/profile/overview/state-distribution.tsx index c3533018cb3..ca73fa46592 100644 --- a/web/core/components/profile/overview/state-distribution.tsx +++ b/web/core/components/profile/overview/state-distribution.tsx @@ -1,4 +1,5 @@ // ui +import { useTranslation } from "@plane/i18n"; import { IUserProfileData, IUserStateDistribution } from "@plane/types"; import { Card } from "@plane/ui"; import { ProfileEmptyState, PieGraph } from "@/components/ui"; @@ -15,11 +16,12 @@ type Props = { }; export const ProfileStateDistribution: React.FC = ({ stateDistribution, userProfile }) => { + const { t } = useTranslation(); if (!userProfile) return null; return (
-

Issues by state

+

{t("profile.stats.state_distribution.title")}

{userProfile.state_distribution.length > 0 ? (
@@ -77,8 +79,8 @@ export const ProfileStateDistribution: React.FC = ({ stateDistribution, u
) : ( )} diff --git a/web/core/components/profile/overview/stats.tsx b/web/core/components/profile/overview/stats.tsx index 50f6b0ae02f..cf0f15d3e1a 100644 --- a/web/core/components/profile/overview/stats.tsx +++ b/web/core/components/profile/overview/stats.tsx @@ -5,6 +5,7 @@ import { useParams } from "next/navigation"; // ui import { UserCircle2 } from "lucide-react"; +import { useTranslation } from "@plane/i18n"; import { IUserProfileData } from "@plane/types"; import { CreateIcon, LayerStackIcon, Loader, Card, ECardSpacing, ECardDirection } from "@plane/ui"; // types @@ -16,30 +17,32 @@ type Props = { export const ProfileStats: React.FC = ({ userProfile }) => { const { workspaceSlug, userId } = useParams(); + const { t } = useTranslation(); + const overviewCards = [ { icon: CreateIcon, route: "created", - title: "Issues created", + i18n_title: "profile.stats.created", value: userProfile?.created_issues ?? "...", }, { icon: UserCircle2, route: "assigned", - title: "Issues assigned", + i18n_title: "profile.stats.assigned", value: userProfile?.assigned_issues ?? "...", }, { icon: LayerStackIcon, route: "subscribed", - title: "Issues subscribed", + i18n_title: "profile.stats.subscribed", value: userProfile?.subscribed_issues ?? "...", }, ]; return (
-

Overview

+

{t("profile.stats.overview")}

{userProfile ? (
{overviewCards.map((card) => ( @@ -49,7 +52,7 @@ export const ProfileStats: React.FC = ({ userProfile }) => {
-

{card.title}

+

{t(card.i18n_title)}

{card.value}

diff --git a/web/core/components/profile/overview/workload.tsx b/web/core/components/profile/overview/workload.tsx index 94ebc2fe6d8..9f1283cdf90 100644 --- a/web/core/components/profile/overview/workload.tsx +++ b/web/core/components/profile/overview/workload.tsx @@ -1,4 +1,5 @@ // types +import { useTranslation } from "@plane/i18n"; import { IUserStateDistribution } from "@plane/types"; import { Card, ECardDirection, ECardSpacing } from "@plane/ui"; import { STATE_GROUPS } from "@/constants/state"; @@ -8,34 +9,38 @@ type Props = { stateDistribution: IUserStateDistribution[]; }; -export const ProfileWorkload: React.FC = ({ stateDistribution }) => ( -
-

Workload

-
- {stateDistribution.map((group) => ( -
- - - - ))} +export const ProfileWorkload: React.FC = ({ stateDistribution }) => { + const { t } = useTranslation(); + + return ( + -); + ); +}; diff --git a/web/core/components/profile/sidebar.tsx b/web/core/components/profile/sidebar.tsx index 11e10184add..d3e007ea370 100644 --- a/web/core/components/profile/sidebar.tsx +++ b/web/core/components/profile/sidebar.tsx @@ -11,6 +11,7 @@ import { Disclosure, Transition } from "@headlessui/react"; // plane helpers import { useOutsideClickDetector } from "@plane/hooks"; // types +import { useTranslation } from "@plane/i18n"; import { IUserProfileProjectSegregation } from "@plane/types"; // plane ui import { Loader, Tooltip } from "@plane/ui"; @@ -42,6 +43,7 @@ export const ProfileSidebar: FC = observer((props) => { const { profileSidebarCollapsed, toggleProfileSidebar } = useAppTheme(); const { getProjectById } = useProject(); const { isMobile } = usePlatformOS(); + const { t } = useTranslation(); // derived values const userData = userProjectsData?.user_data; @@ -55,11 +57,11 @@ export const ProfileSidebar: FC = observer((props) => { const userDetails = [ { - label: "Joined on", + i18n_label: "profile.details.joined_on", value: renderFormattedDate(userData?.date_joined ?? ""), }, { - label: "Timezone", + i18n_label: "profile.details.time_zone", value: , }, ]; @@ -131,8 +133,8 @@ export const ProfileSidebar: FC = observer((props) => {
{userDetails.map((detail) => ( -
-
{detail.label}
+
+
{t(detail.i18n_label)}
{detail.value}
))} @@ -229,28 +231,36 @@ export const ProfileSidebar: FC = observer((props) => {
Created
-
{project.created_issues} Issues
+
+ {project.created_issues} {t("issues")} +
Assigned
-
{project.assigned_issues} Issues
+
+ {project.assigned_issues} {t("issues")} +
Due
-
{project.pending_issues} Issues
+
+ {project.pending_issues} {t("issues")} +
Completed
-
{project.completed_issues} Issues
+
+ {project.completed_issues} {t("issues")} +