From 04522a256620901a939aa674177d284e9c7e50c9 Mon Sep 17 00:00:00 2001
From: Osama Mabkhot <99215291+O2sa@users.noreply.github.com>
Date: Tue, 14 Apr 2026 06:03:55 +0300
Subject: [PATCH] feat: Add i18n Support (EN/AR)
---
app/page.tsx | 6 +-
app/providers.tsx | 7 +-
components/breakdown-bars.tsx | 105 ++++++++++++++++++------------
components/compare-form.tsx | 18 +++---
components/comparison-chart.tsx | 20 +++---
components/comparison-table.tsx | 11 ++--
components/insights-list.tsx | 5 +-
components/language-provider.tsx | 26 ++++++++
components/language-switcher.tsx | 23 +++++++
components/result-dashboard.tsx | 56 ++++++++--------
components/top-list.tsx | 43 ++++++-------
lib/i18n.ts | 106 +++++++++++++++++++++++++++++++
locales/ar.json | 55 ++++++++++++++++
locales/en.json | 56 ++++++++++++++++
14 files changed, 419 insertions(+), 118 deletions(-)
create mode 100644 components/language-provider.tsx
create mode 100644 components/language-switcher.tsx
create mode 100644 lib/i18n.ts
create mode 100644 locales/ar.json
create mode 100644 locales/en.json
diff --git a/app/page.tsx b/app/page.tsx
index ed3a79e..4adc5f4 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -5,6 +5,7 @@ import { CompareForm } from "../components/compare-form";
import { ResultDashboard } from "../components/result-dashboard";
import { DashboardSkeleton } from "../components/skeletons";
import { UserResult } from "@/types/user-result";
+import { LanguageSwitcher } from "@/components/language-switcher";
type ApiResponse = {
success: boolean;
@@ -74,7 +75,10 @@ export default function HomePage() {
DevImpact
-
+
+
diff --git a/app/providers.tsx b/app/providers.tsx
index 9b467c1..48e0a87 100644
--- a/app/providers.tsx
+++ b/app/providers.tsx
@@ -1,11 +1,12 @@
"use client";
+import { LanguageProvider } from "@/components/language-provider";
import { TooltipProvider } from "@/components/ui/tooltip";
export default function Providers({ children }: { children: React.ReactNode }) {
return (
-
- {children}
-
+
+ {children}{" "}
+
);
}
diff --git a/components/breakdown-bars.tsx b/components/breakdown-bars.tsx
index db00b6b..5c1c8c0 100644
--- a/components/breakdown-bars.tsx
+++ b/components/breakdown-bars.tsx
@@ -1,7 +1,13 @@
import { UserResult } from "@/types/user-result";
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "./ui/card";
import { Progress } from "./ui/progress";
-
+import { useTranslation } from "./language-provider";
type Props = {
user1: UserResult;
@@ -15,45 +21,64 @@ const items = [
];
export function BreakdownBars({ user1, user2 }: Props) {
- const getMaxScore = (score1: number, score2: number) => Math.max(score1, score2, 1)
-
+ const getMaxScore = (score1: number, score2: number) =>
+ Math.max(score1, score2, 1);
+ const { t,dir } = useTranslation();
return (
-
-
- Detailed Breakdown
- Progress bars showing relative performance
-
-
- {["repoScore", "prScore", "contributionScore"].map((metric) => {
- const user1Value = user1[metric as keyof UserResult] as number
- const user2Value = user2[metric as keyof UserResult] as number
- const maxVal = getMaxScore(user1Value, user2Value)
- const metricLabel = metric === "repoScore" ? "Repository Score" : metric === "prScore" ? "Pull Request Score" : "Contribution Score"
- return (
-
-
- {metricLabel}
-
- {user1.username}: {user1Value} | {user2.username}: {user2Value}
-
-
-
-
-
{user1.username}
-
-
{user1Value}
-
-
-
{user2.username}
-
-
{user2Value}
-
-
-
- )
- })}
-
-
+
+
+ {t('breakdown.title')}
+
+ {t('breakdown.description')}
+
+
+
+ {["repoScore", "prScore", "contributionScore"].map((metric) => {
+ const user1Value = user1[metric as keyof UserResult] as number;
+ const user2Value = user2[metric as keyof UserResult] as number;
+ const maxVal = getMaxScore(user1Value, user2Value);
+ const metricLabel =
+ metric === "repoScore"
+ ? "breakdown.repo"
+ : metric === "prScore"
+ ? "breakdown.pr"
+ : "breakdown.contribution";
+ return (
+
+
+ {t(metricLabel)}
+
+ {user1.username}: {user1Value} | {user2.username}:{" "}
+ {user2Value}
+
+
+
+
+
+ {user1.username}
+
+
+
{user1Value}
+
+
+
+ {user2.username}
+
+
+
{user2Value}
+
+
+
+ );
+ })}
+
+
);
}
diff --git a/components/compare-form.tsx b/components/compare-form.tsx
index a07f593..512eb45 100644
--- a/components/compare-form.tsx
+++ b/components/compare-form.tsx
@@ -9,6 +9,7 @@ import {
CardTitle,
} from "./ui/card";
import { Alert, AlertDescription } from "./ui/alert";
+import { useTranslation } from "./language-provider";
type CompareFormProps = {
data?: any;
@@ -27,6 +28,7 @@ export function CompareForm({
reset,
error,
}: CompareFormProps) {
+ const { t } = useTranslation();
const [username1, setUsername1] = useState("pbiggar");
const [username2, setUsername2] = useState("CoralineAda");
@@ -54,22 +56,20 @@ export function CompareForm({
);
@@ -71,46 +66,46 @@ export function TopList({ userResults }: Props) {