Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0",
"use-debounce": "^10.1.1",
"zod": "^4.4.3"
"zod": "^4.4.3",
"react-i18next": "^15.5.0",
"i18next": "^25.2.0",
"i18next-browser-languagedetector": "^8.0.2"
},
"devDependencies": {
"@axe-core/playwright": "^4.12.1",
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ApolloProvider } from '@apollo/client/react';
import { lazy, Suspense } from 'react';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n/config';
import {
createBrowserRouter,
createRoutesFromElements,
Expand Down Expand Up @@ -277,8 +279,10 @@ function App() {
return (
<ApolloProvider client={client}>
<ThemeProvider>
<Toaster />
<RouterProvider router={router} />
<I18nextProvider i18n={i18n}>
<Toaster />
<RouterProvider router={router} />
</I18nextProvider>
</ThemeProvider>
</ApolloProvider>
);
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/dashboard/chart-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ResponsiveContainer } from 'recharts';
import { DashboardError } from '@/components/dashboard/dashboard-error';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Spinner } from '@/components/ui/spinner';
import { useI18n } from '@/hooks/use-i18n';

export function ChartCard({
children,
Expand All @@ -26,6 +27,8 @@ export function ChartCard({
loading?: boolean;
title: ReactNode;
}) {
const { t } = useI18n();

return (
<Card className={className}>
<CardHeader>
Expand Down Expand Up @@ -54,7 +57,7 @@ export function ChartCard({
style={{ height }}
>
<BarChart2 className="text-muted-foreground/30 size-10" />
<p className="text-muted-foreground text-sm">No data for this period</p>
<p className="text-muted-foreground text-sm">{t('dashboard.noDataForPeriod')}</p>
</div>
) : (
<ResponsiveContainer
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/dashboard/dashboard-error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { CSSProperties } from 'react';

import { AlertCircle } from 'lucide-react';

import { useI18n } from '@/hooks/use-i18n';
import { cn } from '@/lib/utils';

export function DashboardError({
Expand All @@ -13,13 +14,15 @@ export function DashboardError({
iconClassName?: string;
style?: CSSProperties;
}) {
const { t } = useI18n();

return (
<div
className={cn('text-muted-foreground flex flex-col items-center justify-center gap-2', className)}
style={style}
>
<AlertCircle className={cn('text-muted-foreground/40 size-6', iconClassName)} />
<p className="text-sm">Couldn't load</p>
<p className="text-sm">{t('errors.couldntLoad')}</p>
</div>
);
}
7 changes: 6 additions & 1 deletion frontend/src/components/dashboard/metric-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AlertCircle } from 'lucide-react';

import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
import { useI18n } from '@/hooks/use-i18n';

export function MetricCard({
className,
Expand All @@ -22,6 +23,8 @@ export function MetricCard({
title: ReactNode;
value: ReactNode;
}) {
const { t } = useI18n();

return (
<Card className={className}>
<CardHeader className="flex flex-row items-center justify-between pb-2">
Expand All @@ -48,7 +51,9 @@ export function MetricCard({
(loading ? (
<Skeleton className="mt-1 h-3 w-32" />
) : (
<p className="text-muted-foreground text-xs">{error ? "Couldn't load" : description}</p>
<p className="text-muted-foreground text-xs">
{error ? t('errors.couldntLoad') : description}
</p>
))}
</CardContent>
</Card>
Expand Down
46 changes: 25 additions & 21 deletions frontend/src/components/layouts/main/main-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
UserIcon,
} from 'lucide-react';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Link, useLocation, useMatch, useParams } from 'react-router-dom';

import type { Flow } from '@/providers/sidebar-flows-provider';
Expand Down Expand Up @@ -62,6 +63,7 @@ interface FlowMenuItemProps {
}

export function MainSidebar() {
const { t } = useTranslation();
const location = useLocation();
const isDashboardActive = useMatch('/dashboard');
const isFlowsActive = useMatch('/flows/*');
Expand Down Expand Up @@ -107,7 +109,7 @@ export function MainSidebar() {
<Logo className="hover:animate-logo-spin size-6" />
</div>
<div className="grid flex-1 text-left leading-tight">
<span className="truncate font-semibold">PentAGI</span>
<span className="truncate font-semibold">{t('sidebar.appName')}</span>
</div>
</SidebarMenuItem>
</SidebarMenu>
Expand All @@ -120,7 +122,7 @@ export function MainSidebar() {
<SidebarMenuButton asChild>
<Link to={routes.newFlow}>
<Plus />
New Flow
{t('sidebar.newFlow')}
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
Expand All @@ -131,7 +133,7 @@ export function MainSidebar() {
>
<Link to={routes.dashboard}>
<LayoutDashboard />
Dashboard
{t('sidebar.dashboard')}
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
Expand All @@ -142,7 +144,7 @@ export function MainSidebar() {
>
<Link to={routes.flows}>
<GitFork />
Flows
{t('sidebar.flows')}
</Link>
</SidebarMenuButton>
<SidebarMenuAction
Expand All @@ -151,7 +153,7 @@ export function MainSidebar() {
showOnHover
>
<Link
aria-label="New flow"
aria-label={t('sidebar.newFlowAction')}
to={routes.newFlow}
>
<Plus />
Expand All @@ -165,7 +167,7 @@ export function MainSidebar() {
>
<Link to={routes.templates}>
<FileText />
Templates
{t('sidebar.templates')}
</Link>
</SidebarMenuButton>
<SidebarMenuAction
Expand All @@ -174,7 +176,7 @@ export function MainSidebar() {
showOnHover
>
<Link
aria-label="New template"
aria-label={t('sidebar.newTemplateAction')}
to={routes.newTemplate}
>
<Plus />
Expand All @@ -188,14 +190,14 @@ export function MainSidebar() {
>
<Link to={routes.resources}>
<Folder />
Resources
{t('sidebar.resources')}
</Link>
</SidebarMenuButton>
<SidebarMenuAction
className="data-[state=open]:bg-accent rounded-sm"
onClick={resourcesUpload.openFilePicker}
showOnHover
title="Upload file"
title={t('sidebar.uploadFile')}
type="button"
>
<Plus />
Expand All @@ -208,7 +210,7 @@ export function MainSidebar() {
>
<Link to={routes.knowledges}>
<LibraryBig />
Knowledges
{t('sidebar.knowledges')}
</Link>
</SidebarMenuButton>
<SidebarMenuAction
Expand All @@ -217,7 +219,7 @@ export function MainSidebar() {
showOnHover
>
<Link
aria-label="New knowledge"
aria-label={t('sidebar.newKnowledgeAction')}
to={routes.newKnowledge}
>
<Plus />
Expand All @@ -232,7 +234,7 @@ export function MainSidebar() {
<SidebarGroup>
<SidebarGroupLabel className="flex items-center gap-2">
<Clock />
Recent Flows
{t('sidebar.recentFlows')}
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
Expand All @@ -254,7 +256,7 @@ export function MainSidebar() {
<SidebarGroup>
<SidebarGroupLabel className="flex items-center gap-2">
<Star />
Favorite Flows
{t('sidebar.favoriteFlows')}
</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
Expand Down Expand Up @@ -284,7 +286,7 @@ export function MainSidebar() {
to={routes.settings.root}
>
<Settings />
Settings
{t('sidebar.settings')}
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
Expand Down Expand Up @@ -335,29 +337,29 @@ export function MainSidebar() {
onSelect={(event) => event.preventDefault()}
>
<Settings2 />
Theme
{t('sidebar.theme')}
<Tabs
className="-my-1.5 -mr-2 ml-auto"
onValueChange={(value) => setTheme(value as Theme)}
value={theme || 'system'}
>
<TabsList className="dark:bg-background h-7 p-0.5">
<TabsTrigger
aria-label="System theme"
aria-label={t('sidebar.systemTheme')}
className="dark:data-[state=active]:bg-card h-6 px-2"
value="system"
>
<Monitor className="size-4" />
</TabsTrigger>
<TabsTrigger
aria-label="Light theme"
aria-label={t('sidebar.lightTheme')}
className="dark:data-[state=active]:bg-card h-6 px-2"
value="light"
>
<Sun className="size-4" />
</TabsTrigger>
<TabsTrigger
aria-label="Dark theme"
aria-label={t('sidebar.darkTheme')}
className="dark:data-[state=active]:bg-card h-6 px-2"
value="dark"
>
Expand All @@ -373,13 +375,13 @@ export function MainSidebar() {
to={routes.settings.account}
>
<UserIcon className="mr-2 size-4" />
Profile
{t('sidebar.profile')}
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem onClick={() => logout()}>
<LogOut className="mr-2 size-4" />
Log out
{t('sidebar.logout')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
Expand All @@ -403,6 +405,8 @@ export function MainSidebar() {
}

function FlowMenuItem({ activeFlowId, flow, isFavorite, onToggleFavorite }: FlowMenuItemProps) {
const { t } = useTranslation();

return (
<SidebarMenuItem>
<SidebarMenuButton
Expand All @@ -420,7 +424,7 @@ function FlowMenuItem({ activeFlowId, flow, isFavorite, onToggleFavorite }: Flow
</Link>
</SidebarMenuButton>
<SidebarMenuAction
aria-label="Toggle favorite"
aria-label={t('sidebar.toggleFavorite')}
aria-pressed={isFavorite}
className="data-[state=open]:bg-accent rounded-sm"
onClick={() => onToggleFavorite(flow.id)}
Expand Down
Loading