fix(i18n): translate submit button, density/view toggles; rename watchlist guide to Merkliste; add guide help buttons
Build & Push Docker Image / build (push) Successful in 2m31s

This commit is contained in:
opencode
2026-08-04 20:43:36 +02:00
parent 63aa14914f
commit 70e72dac71
23 changed files with 106 additions and 47 deletions
@@ -15,6 +15,7 @@ import {
import { useQueryClient } from "@tanstack/react-query";
import { useAuth } from "@/hooks/use-auth";
import { Button } from "@/components/ui/button";
import { GuideHelp } from "@/components/guide-help";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
@@ -105,7 +106,10 @@ export function AdminToolsTab() {
<Card>
<CardHeader className="flex flex-row items-center justify-between gap-4 flex-wrap">
<div className="space-y-1.5">
<CardTitle>{t("adminTools.allTools")}</CardTitle>
<CardTitle className="flex items-center gap-2">
{t("adminTools.allTools")}
<GuideHelp guide="administration" label={t("adminTools.allTools")} />
</CardTitle>
<CardDescription>
{selectedIds.length > 0 ? t("adminTools.selected", { count: selectedIds.length }) : t("adminTools.toolCount", { count: allTools.length })}
</CardDescription>
@@ -1,5 +1,6 @@
import { Slider } from "@/components/ui/slider";
import { Maximize2, Minimize2 } from "lucide-react";
import { useTranslation } from "react-i18next";
export type Density = "cozy" | "compact";
@@ -10,8 +11,13 @@ export function DensityToggle({
value: Density;
onValueChange: (d: Density) => void;
}) {
const { t } = useTranslation();
const densityLabel = value === "compact" ? t("common.densityCompact") : t("common.densityComfortable");
return (
<div className="flex items-center gap-2" title={`Density: ${value === "compact" ? "Compact" : "Comfortable"}`}>
<div
className="flex items-center gap-2"
title={t("common.densityTitle", { density: densityLabel })}
>
<Maximize2 className="w-4 h-4 text-muted-foreground" aria-hidden />
<Slider
className="w-16"
@@ -20,7 +26,7 @@ export function DensityToggle({
step={1}
value={[value === "compact" ? 1 : 0]}
onValueChange={([v]) => onValueChange(v === 1 ? "compact" : "cozy")}
aria-label="List density"
aria-label={t("common.listDensity")}
/>
<Minimize2 className="w-4 h-4 text-muted-foreground" aria-hidden />
</div>
@@ -105,7 +105,7 @@ export function FilterPopover({
step={0.5}
value={[minRating ?? 0]}
onValueChange={([v]) => onChange({ minRating: v })}
aria-label="Minimum rating"
aria-label={t("filter.minRating")}
/>
<span className="text-sm tabular-nums w-8 text-right text-muted-foreground">
{minRating != null ? `${minRating.toFixed(1)}+` : t("filter.any")}
@@ -17,6 +17,7 @@ import {
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { PasswordInput } from "@/components/password-input";
import { GuideHelp } from "@/components/guide-help";
import { useToast } from "@/hooks/use-toast";
import { useChangeMyPassword, useGetPasswordRedirect, getGetPasswordRedirectQueryKey } from "@workspace/api-client-react";
import { useQueryClient } from "@tanstack/react-query";
@@ -164,7 +165,10 @@ export function UserMenu() {
<Dialog open={pwOpen} onOpenChange={setPwOpen}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>{t("auth.changePassword")}</DialogTitle>
<DialogTitle className="flex items-center gap-2">
{t("auth.changePassword")}
<GuideHelp guide="konto" label={t("auth.changePassword")} />
</DialogTitle>
</DialogHeader>
{!user?.isLocal ? (
<div className="space-y-4 py-2">
@@ -193,7 +197,7 @@ export function UserMenu() {
<PasswordInput
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
placeholder="min. 6 characters"
placeholder={t("auth.passwordMinLength")}
data-testid="input-new-password"
/>
</div>
@@ -1,12 +1,13 @@
import { LayoutGrid, List, Rows3 } from "lucide-react";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
import { useTranslation } from "react-i18next";
export type ViewMode = "grid" | "table" | "rows";
const OPTIONS: { value: ViewMode; label: string; Icon: typeof LayoutGrid }[] = [
{ value: "grid", label: "Grid", Icon: LayoutGrid },
{ value: "table", label: "Table", Icon: List },
{ value: "rows", label: "Rows", Icon: Rows3 },
const OPTIONS: { value: ViewMode; labelKey: string; Icon: typeof LayoutGrid }[] = [
{ value: "grid", labelKey: "common.viewGrid", Icon: LayoutGrid },
{ value: "table", labelKey: "common.viewTable", Icon: List },
{ value: "rows", labelKey: "common.viewRows", Icon: Rows3 },
];
export function ViewToggle({
@@ -16,6 +17,7 @@ export function ViewToggle({
value: ViewMode;
onValueChange: (v: ViewMode) => void;
}) {
const { t } = useTranslation();
return (
<ToggleGroup
type="single"
@@ -25,10 +27,16 @@ export function ViewToggle({
}}
variant="outline"
size="sm"
aria-label="View mode"
aria-label={t("common.viewMode")}
>
{OPTIONS.map(({ value: v, label, Icon }) => (
<ToggleGroupItem key={v} value={v} aria-label={label} title={label} data-testid={`view-${v}`}>
{OPTIONS.map(({ value: v, labelKey, Icon }) => (
<ToggleGroupItem
key={v}
value={v}
aria-label={t(labelKey)}
title={t(labelKey)}
data-testid={`view-${v}`}
>
<Icon className="w-4 h-4" />
</ToggleGroupItem>
))}