i18n complete: all 16 components translated (CZ/HE/RU/UA)
- Custom i18n provider with React Context + localStorage - Hebrew RTL support (dir=rtl on html) - All pages + components use t() calls - FullCalendar + dates locale-aware - Language selector in Settings wired to context Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useRef, useEffect } from "react";
|
||||
import { Group } from "@/lib/api";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
|
||||
interface GroupSelectorProps {
|
||||
groups: Group[];
|
||||
@@ -16,6 +17,7 @@ export default function GroupSelector({
|
||||
}: GroupSelectorProps) {
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const activeRef = useRef<HTMLButtonElement>(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Scroll active button into view
|
||||
useEffect(() => {
|
||||
@@ -46,7 +48,7 @@ export default function GroupSelector({
|
||||
: "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700 min-h-[44px]"
|
||||
}`}
|
||||
>
|
||||
Vse
|
||||
{t("tasks.all")}
|
||||
</button>
|
||||
{groups.map((g) => (
|
||||
<button
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useState, useRef } from "react";
|
||||
import { Task } from "@/lib/api";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import StatusBadge from "./StatusBadge";
|
||||
import Link from "next/link";
|
||||
import { useSwipeable } from "react-swipeable";
|
||||
@@ -23,6 +24,7 @@ function isDone(status: string): boolean {
|
||||
}
|
||||
|
||||
export default function TaskCard({ task, onComplete }: TaskCardProps) {
|
||||
const { t, locale } = useTranslation();
|
||||
const groupColor = task.group_color || "#6b7280";
|
||||
const priorityColor = PRIORITY_COLORS[task.priority] || PRIORITY_COLORS.medium;
|
||||
const taskDone = isDone(task.status);
|
||||
@@ -32,6 +34,8 @@ export default function TaskCard({ task, onComplete }: TaskCardProps) {
|
||||
|
||||
const SWIPE_THRESHOLD = 120;
|
||||
|
||||
const dateLocale = locale === "ua" ? "uk-UA" : locale === "cs" ? "cs-CZ" : locale === "he" ? "he-IL" : "ru-RU";
|
||||
|
||||
const swipeHandlers = useSwipeable({
|
||||
onSwiping: (e) => {
|
||||
// Only allow right swipe for complete gesture
|
||||
@@ -80,7 +84,7 @@ export default function TaskCard({ task, onComplete }: TaskCardProps) {
|
||||
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
<span className="text-sm">Hotovo</span>
|
||||
<span className="text-sm">{t("tasks.status.done")}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -155,7 +159,7 @@ export default function TaskCard({ task, onComplete }: TaskCardProps) {
|
||||
<svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
</svg>
|
||||
{new Date(task.due_at).toLocaleDateString("cs-CZ")}
|
||||
{new Date(task.due_at).toLocaleDateString(dateLocale)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -165,7 +169,7 @@ export default function TaskCard({ task, onComplete }: TaskCardProps) {
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-full flex-shrink-0"
|
||||
style={{ backgroundColor: priorityColor }}
|
||||
title={task.priority}
|
||||
title={t(`tasks.priority.${task.priority}`)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user