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:
Claude CLI Agent
2026-03-29 13:19:02 +00:00
parent 235bcab97f
commit 4fae1c5a06
15 changed files with 386 additions and 114 deletions

View File

@@ -3,6 +3,7 @@
import { useState, useRef, useEffect } from "react";
import { useRouter } from "next/navigation";
import { useAuth } from "@/lib/auth";
import { useTranslation } from "@/lib/i18n";
interface ChatMessage {
id: string;
@@ -13,6 +14,7 @@ interface ChatMessage {
export default function ChatPage() {
const { token, user } = useAuth();
const { t, locale } = useTranslation();
const router = useRouter();
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [input, setInput] = useState("");
@@ -20,6 +22,8 @@ export default function ChatPage() {
const messagesEndRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
const timeLocale = locale === "ua" ? "uk-UA" : locale === "cs" ? "cs-CZ" : locale === "he" ? "he-IL" : "ru-RU";
useEffect(() => {
if (!token) {
router.replace("/login");
@@ -63,7 +67,7 @@ export default function ChatPage() {
const assistantMsg: ChatMessage = {
id: (Date.now() + 1).toString(),
role: "assistant",
content: data.reply || data.message || "Omlouvám se, nemohl jsem zpracovat vaši zprávu.",
content: data.reply || data.message || t("chat.processError"),
timestamp: new Date(),
};
setMessages((prev) => [...prev, assistantMsg]);
@@ -71,7 +75,7 @@ export default function ChatPage() {
const errorMsg: ChatMessage = {
id: (Date.now() + 1).toString(),
role: "assistant",
content: "Chat asistent je momentálně nedostupný. Zkuste to prosím později.",
content: t("chat.unavailable"),
timestamp: new Date(),
};
setMessages((prev) => [...prev, errorMsg]);
@@ -100,8 +104,8 @@ export default function ChatPage() {
</svg>
</div>
<div>
<h1 className="font-semibold">AI Asistent</h1>
<p className="text-xs text-muted">Zeptejte se na cokoliv ohledně vašich úkolů</p>
<h1 className="font-semibold">{t("chat.title")}</h1>
<p className="text-xs text-muted">{t("chat.subtitle")}</p>
</div>
</div>
@@ -114,9 +118,9 @@ export default function ChatPage() {
<path strokeLinecap="round" strokeLinejoin="round" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
</div>
<p className="text-muted text-lg font-medium">Začněte konverzaci</p>
<p className="text-muted text-lg font-medium">{t("chat.startConversation")}</p>
<p className="text-muted text-sm mt-1">
Napište zprávu a AI asistent vám pomůže s úkoly
{t("chat.helpText")}
</p>
</div>
)}
@@ -139,7 +143,7 @@ export default function ChatPage() {
msg.role === "user" ? "text-blue-200" : "text-muted"
}`}
>
{msg.timestamp.toLocaleTimeString("cs-CZ", { hour: "2-digit", minute: "2-digit" })}
{msg.timestamp.toLocaleTimeString(timeLocale, { hour: "2-digit", minute: "2-digit" })}
</p>
</div>
</div>
@@ -168,7 +172,7 @@ export default function ChatPage() {
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Napište zprávu..."
placeholder={t("chat.placeholder")}
rows={1}
className="flex-1 px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-2xl bg-white dark:bg-gray-800 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none resize-none text-sm"
style={{ maxHeight: "120px" }}
@@ -177,7 +181,7 @@ export default function ChatPage() {
onClick={handleSend}
disabled={loading || !input.trim()}
className="p-3 bg-blue-600 hover:bg-blue-700 disabled:opacity-50 text-white rounded-full transition-colors flex-shrink-0"
aria-label="Odeslat"
aria-label={t("chat.send")}
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />