feat(i18n): full app + docs localization (de/en)
Build & Push Docker Image / build (push) Successful in 2m33s

- translate remaining pages/components (admin, analytics, redundancy,
  trash, compare, browse, watchlist, admin tools tab, category combobox,
  theme toggle, tool preview card, tool-new/edit) to t() calls
- locales: 453 keys each, parity verified
- docs: bilingual handbook + release notes via *.en.md variants,
  language-aware docs.tsx (markdown paths, nav titles, search index),
  LanguageSwitcher in docs header
- generate-docs: emit per-locale handbook/release/search output,
  localized index.json fields (fileEn/titleEn), en-aware snapshots
This commit is contained in:
opencode
2026-08-04 08:35:05 +02:00
parent a65e2eb92c
commit 3de59ccaaf
77 changed files with 3786 additions and 440 deletions
+18 -16
View File
@@ -5,6 +5,7 @@ import {
useGetRatingDistribution,
GetTopToolsMetric
} from "@workspace/api-client-react";
import { useTranslation } from "react-i18next";
import { Layout } from "@/components/layout";
import { GuideHelp } from "@/components/guide-help";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
@@ -17,6 +18,7 @@ import {
import { BarChart3, TrendingUp, Layers, Activity } from "lucide-react";
export default function Analytics() {
const { t } = useTranslation();
const { data: summary, isLoading: loadingSummary } = useGetAnalyticsSummary();
const { data: topTools, isLoading: loadingTopTools } = useGetTopTools({
@@ -50,10 +52,10 @@ export default function Analytics() {
<div className="space-y-6 pb-10">
<div>
<h1 className="text-3xl font-bold tracking-tight mb-2 flex items-center gap-2">
Platform Analytics
<GuideHelp guide="analytics" label="Platform Analytics" />
{t("analytics.title")}
<GuideHelp guide="analytics" label={t("analytics.title")} />
</h1>
<p className="text-muted-foreground">Macro-level insights into tool performance and community engagement.</p>
<p className="text-muted-foreground">{t("analytics.subtitle")}</p>
</div>
{/* Top KPI Cards */}
@@ -61,7 +63,7 @@ export default function Analytics() {
<Card>
<CardContent className="p-6">
<div className="flex items-center justify-between mb-4">
<span className="text-sm font-medium text-muted-foreground">Total Tools Indexed</span>
<span className="text-sm font-medium text-muted-foreground">{t("analytics.totalToolsIndexed")}</span>
<Layers className="w-4 h-4 text-muted-foreground" />
</div>
{loadingSummary ? <Skeleton className="h-8 w-16" /> : (
@@ -73,7 +75,7 @@ export default function Analytics() {
<Card>
<CardContent className="p-6">
<div className="flex items-center justify-between mb-4">
<span className="text-sm font-medium text-muted-foreground">Total Ratings Cast</span>
<span className="text-sm font-medium text-muted-foreground">{t("analytics.totalRatingsCast")}</span>
<Activity className="w-4 h-4 text-muted-foreground" />
</div>
{loadingSummary ? <Skeleton className="h-8 w-16" /> : (
@@ -85,7 +87,7 @@ export default function Analytics() {
<Card>
<CardContent className="p-6">
<div className="flex items-center justify-between mb-4">
<span className="text-sm font-medium text-muted-foreground">Active Categories</span>
<span className="text-sm font-medium text-muted-foreground">{t("analytics.activeCategories")}</span>
<BarChart3 className="w-4 h-4 text-muted-foreground" />
</div>
{loadingSummary ? <Skeleton className="h-8 w-16" /> : (
@@ -97,7 +99,7 @@ export default function Analytics() {
<Card>
<CardContent className="p-6">
<div className="flex items-center justify-between mb-4">
<span className="text-sm font-medium text-muted-foreground">Avg Global Score</span>
<span className="text-sm font-medium text-muted-foreground">{t("analytics.avgGlobalScore")}</span>
<TrendingUp className="w-4 h-4 text-muted-foreground" />
</div>
{loadingSummary ? <Skeleton className="h-8 w-16" /> : (
@@ -112,8 +114,8 @@ export default function Analytics() {
{/* Top Tools Chart */}
<Card className="col-span-1 lg:col-span-2">
<CardHeader>
<CardTitle>Top 8 Tools by Combined Score</CardTitle>
<CardDescription>Highest rated tools across the platform</CardDescription>
<CardTitle>{t("analytics.top8Tools")}</CardTitle>
<CardDescription>{t("analytics.top8ToolsSub")}</CardDescription>
</CardHeader>
<CardContent>
{loadingTopTools ? (
@@ -140,8 +142,8 @@ export default function Analytics() {
{/* Category Breakdown */}
<Card>
<CardHeader>
<CardTitle>Tools by Category</CardTitle>
<CardDescription>Distribution of tools across categories</CardDescription>
<CardTitle>{t("analytics.toolsByCategory")}</CardTitle>
<CardDescription>{t("analytics.toolsByCategorySub")}</CardDescription>
</CardHeader>
<CardContent>
{loadingCategories ? (
@@ -153,7 +155,7 @@ export default function Analytics() {
<PolarGrid stroke="hsl(var(--border))" />
<PolarAngleAxis dataKey="category" tick={{ fill: 'hsl(var(--foreground))', fontSize: 12 }} />
<PolarRadiusAxis angle={30} domain={[0, 'auto']} tick={false} axisLine={false} />
<Radar name="Tools" dataKey="tools" stroke="hsl(var(--primary))" fill="hsl(var(--primary))" fillOpacity={0.3} />
<Radar name={t("analytics.radarTools")} dataKey="tools" stroke="hsl(var(--primary))" fill="hsl(var(--primary))" fillOpacity={0.3} />
<RechartsTooltip />
</RadarChart>
</ResponsiveContainer>
@@ -165,8 +167,8 @@ export default function Analytics() {
{/* Rating Distributions */}
<Card>
<CardHeader>
<CardTitle>Global Rating Distribution</CardTitle>
<CardDescription>How users are voting across all tools</CardDescription>
<CardTitle>{t("analytics.globalRatingDistribution")}</CardTitle>
<CardDescription>{t("analytics.globalRatingDistributionSub")}</CardDescription>
</CardHeader>
<CardContent>
{loadingDistribution ? (
@@ -174,7 +176,7 @@ export default function Analytics() {
) : (
<div className="space-y-5">
<div>
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2 block">Usefulness</span>
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2 block">{t("detail.usefulness")}</span>
<div className="h-[110px] w-full">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={usefulnessData} margin={{ top: 4, right: 8, left: -20, bottom: 0 }}>
@@ -188,7 +190,7 @@ export default function Analytics() {
</div>
</div>
<div>
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2 block">Usability</span>
<span className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2 block">{t("detail.usability")}</span>
<div className="h-[110px] w-full">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={usabilityData} margin={{ top: 4, right: 8, left: -20, bottom: 0 }}>