From 39b463d1a1a3aecc4ab2ad2e5c9b26fdcce80e10 Mon Sep 17 00:00:00 2001 From: HugeFrog24 <62775760+HugeFrog24@users.noreply.github.com> Date: Sat, 14 Feb 2026 01:19:52 +0100 Subject: [PATCH] Localization and AI chat widget --- docker-compose.yml | 1 - messages/artworks/alice/de.json | 8 +++++-- messages/artworks/alice/en.json | 8 +++++-- messages/artworks/alice/es.json | 8 +++++-- messages/artworks/alice/ka.json | 8 +++++-- messages/artworks/alice/ru.json | 8 +++++-- messages/artworks/alice/tr.json | 8 +++++-- messages/artworks/nini/de.json | 16 ++++++++++---- messages/artworks/nini/en.json | 16 ++++++++++---- messages/artworks/nini/es.json | 16 ++++++++++---- messages/artworks/nini/ka.json | 16 ++++++++++---- messages/artworks/nini/ru.json | 16 ++++++++++---- messages/artworks/nini/tr.json | 16 ++++++++++---- messages/ui/de.json | 6 ++---- messages/ui/en.json | 6 ++---- messages/ui/es.json | 6 ++---- messages/ui/ka.json | 6 ++---- messages/ui/ru.json | 6 ++---- messages/ui/tr.json | 6 ++---- src/app/[locale]/admin/login/page.tsx | 11 +++++----- src/app/[locale]/admin/page.tsx | 2 +- src/app/[locale]/artwork/[id]/page.tsx | 4 ++-- src/app/page.tsx | 3 ++- src/components/ArtworkCard.tsx | 7 +++---- src/components/ArtworkDetailView.tsx | 6 ++---- src/components/ArtworkGrid.tsx | 6 +++--- src/components/Header.tsx | 29 ++++++++++++-------------- src/components/SectionContainer.tsx | 2 +- src/i18n/request.ts | 8 +++---- src/lib/admin-auth.ts | 4 +--- src/proxy.ts | 5 ++--- 31 files changed, 158 insertions(+), 110 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5cb892f..221943a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,7 +28,6 @@ services: - SMTP_PORT=587 - SMTP_USER=smtp-user@example.com - SMTP_PASS=your-smtp-password - - SMTP_FROM_NAME="Your Gallery Name" - SMTP_SECURE=false - SMTP_REQUIRE_TLS=true - JWT_SECRET=your-super-secret-jwt-key-change-this-in-production diff --git a/messages/artworks/alice/de.json b/messages/artworks/alice/de.json index 5bf2334..f58b78e 100644 --- a/messages/artworks/alice/de.json +++ b/messages/artworks/alice/de.json @@ -2,11 +2,15 @@ "Categories": { "paintings": { "title": "Gemälde & Digitale Kunst", - "description": "Traumhafte Gemälde, die Fantasie und Emotion verbinden" + "description": "Traumhafte Gemälde, die Fantasie und Emotion verbinden", + "gallery": "Galerie der Gemälde und digitalen Kunst", + "artwork": "Gemälde" }, "origami": { "title": "Illustrationen", - "description": "Handgezeichnete Tuscheillustrationen, inspiriert von Märchen" + "description": "Handgezeichnete Tuscheillustrationen, inspiriert von Märchen", + "gallery": "Illustrationen-Galerie", + "artwork": "Illustration" } }, "Artworks": { diff --git a/messages/artworks/alice/en.json b/messages/artworks/alice/en.json index ede0132..aa3e699 100644 --- a/messages/artworks/alice/en.json +++ b/messages/artworks/alice/en.json @@ -2,11 +2,15 @@ "Categories": { "paintings": { "title": "Paintings & Digital Art", - "description": "Dreamlike paintings blending fantasy and emotion" + "description": "Dreamlike paintings blending fantasy and emotion", + "gallery": "Paintings & Digital Art gallery", + "artwork": "Paintings & Digital Art artwork" }, "origami": { "title": "Illustrations", - "description": "Hand-drawn and ink illustrations inspired by fairy tales" + "description": "Hand-drawn and ink illustrations inspired by fairy tales", + "gallery": "Illustrations gallery", + "artwork": "Illustration" } }, "Artworks": { diff --git a/messages/artworks/alice/es.json b/messages/artworks/alice/es.json index e007f5d..4320a97 100644 --- a/messages/artworks/alice/es.json +++ b/messages/artworks/alice/es.json @@ -2,11 +2,15 @@ "Categories": { "paintings": { "title": "Pinturas y Arte Digital", - "description": "Pinturas oníricas que mezclan fantasía y emoción" + "description": "Pinturas oníricas que mezclan fantasía y emoción", + "gallery": "Galería de pinturas y arte digital", + "artwork": "Obra de pintura y arte digital" }, "origami": { "title": "Ilustraciones", - "description": "Ilustraciones a mano y tinta inspiradas en cuentos de hadas" + "description": "Ilustraciones a mano y tinta inspiradas en cuentos de hadas", + "gallery": "Galería de ilustraciones", + "artwork": "Ilustración" } }, "Artworks": { diff --git a/messages/artworks/alice/ka.json b/messages/artworks/alice/ka.json index af1b6a7..55ca11c 100644 --- a/messages/artworks/alice/ka.json +++ b/messages/artworks/alice/ka.json @@ -2,11 +2,15 @@ "Categories": { "paintings": { "title": "ნახატები და ციფრული ხელოვნება", - "description": "ოცნებისებური ნახატები, რომლებიც ფანტაზიასა და ემოციას აერთიანებს" + "description": "ოცნებისებური ნახატები, რომლებიც ფანტაზიასა და ემოციას აერთიანებს", + "gallery": "ნახატებისა და ციფრული ხელოვნების გალერეა", + "artwork": "ნახატი" }, "origami": { "title": "ილუსტრაციები", - "description": "ხელით დახატული და მელნის ილუსტრაციები, ზღაპრებით შთაგონებული" + "description": "ხელით დახატული და მელნის ილუსტრაციები, ზღაპრებით შთაგონებული", + "gallery": "ილუსტრაციების გალერეა", + "artwork": "ილუსტრაცია" } }, "Artworks": { diff --git a/messages/artworks/alice/ru.json b/messages/artworks/alice/ru.json index 4b55aa7..c970fab 100644 --- a/messages/artworks/alice/ru.json +++ b/messages/artworks/alice/ru.json @@ -2,11 +2,15 @@ "Categories": { "paintings": { "title": "Картины и цифровое искусство", - "description": "Мечтательные картины, сочетающие фантазию и эмоции" + "description": "Мечтательные картины, сочетающие фантазию и эмоции", + "gallery": "Галерея картин и цифрового искусства", + "artwork": "Картина" }, "origami": { "title": "Иллюстрации", - "description": "Рисунки тушью и акварелью, вдохновлённые сказками" + "description": "Рисунки тушью и акварелью, вдохновлённые сказками", + "gallery": "Галерея иллюстраций", + "artwork": "Иллюстрация" } }, "Artworks": { diff --git a/messages/artworks/alice/tr.json b/messages/artworks/alice/tr.json index 444d044..cdfd89b 100644 --- a/messages/artworks/alice/tr.json +++ b/messages/artworks/alice/tr.json @@ -2,11 +2,15 @@ "Categories": { "paintings": { "title": "Tablolar ve Dijital Sanat", - "description": "Fantezi ve duyguyu harmanlayan rüya gibi tablolar" + "description": "Fantezi ve duyguyu harmanlayan rüya gibi tablolar", + "gallery": "Tablo ve dijital sanat galerisi", + "artwork": "Tablo eseri" }, "origami": { "title": "İllüstrasyonlar", - "description": "Peri masallarından ilham alan el çizimi ve mürekkep illüstrasyonları" + "description": "Peri masallarından ilham alan el çizimi ve mürekkep illüstrasyonları", + "gallery": "İllüstrasyon galerisi", + "artwork": "İllüstrasyon" } }, "Artworks": { diff --git a/messages/artworks/nini/de.json b/messages/artworks/nini/de.json index 042101c..948aa46 100644 --- a/messages/artworks/nini/de.json +++ b/messages/artworks/nini/de.json @@ -2,19 +2,27 @@ "Categories": { "origami": { "title": "Origami-Kreationen", - "description": "Kunstvolle Papierfaltkunst, die Präzision und Kreativität zeigt" + "description": "Kunstvolle Papierfaltkunst, die Präzision und Kreativität zeigt", + "gallery": "Origami-Kreationen-Galerie", + "artwork": "Origami-Kreation" }, "crochet": { "title": "Häkelarbeiten", - "description": "Handgefertigte Häkelstücke, die traditionelle Techniken mit modernem Design verbinden" + "description": "Handgefertigte Häkelstücke, die traditionelle Techniken mit modernem Design verbinden", + "gallery": "Häkelarbeiten-Galerie", + "artwork": "Häkelarbeit" }, "paintings": { "title": "Gemälde", - "description": "Originale Gemälde, die verschiedene Stile und Techniken erkunden" + "description": "Originale Gemälde, die verschiedene Stile und Techniken erkunden", + "gallery": "Gemälde-Galerie", + "artwork": "Gemälde" }, "fingernails": { "title": "Nagelkunst", - "description": "Kreative und detaillierte Nagelkunst-Designs" + "description": "Kreative und detaillierte Nagelkunst-Designs", + "gallery": "Nagelkunst-Galerie", + "artwork": "Nagelkunst-Werk" } }, "Artworks": { diff --git a/messages/artworks/nini/en.json b/messages/artworks/nini/en.json index b54e030..38504df 100644 --- a/messages/artworks/nini/en.json +++ b/messages/artworks/nini/en.json @@ -2,19 +2,27 @@ "Categories": { "origami": { "title": "Origami Creations", - "description": "Intricate paper folding art pieces showcasing precision and creativity" + "description": "Intricate paper folding art pieces showcasing precision and creativity", + "gallery": "Origami Creations gallery", + "artwork": "Origami Creations artwork" }, "crochet": { "title": "Crochet Items", - "description": "Handcrafted crochet pieces combining traditional techniques with modern design" + "description": "Handcrafted crochet pieces combining traditional techniques with modern design", + "gallery": "Crochet Items gallery", + "artwork": "Crochet Items artwork" }, "paintings": { "title": "Paintings", - "description": "Original paintings exploring various styles and techniques" + "description": "Original paintings exploring various styles and techniques", + "gallery": "Paintings gallery", + "artwork": "Paintings artwork" }, "fingernails": { "title": "Fingernail Art", - "description": "Creative and detailed nail art designs" + "description": "Creative and detailed nail art designs", + "gallery": "Fingernail Art gallery", + "artwork": "Fingernail Art artwork" } }, "Artworks": { diff --git a/messages/artworks/nini/es.json b/messages/artworks/nini/es.json index fb42c56..03de57a 100644 --- a/messages/artworks/nini/es.json +++ b/messages/artworks/nini/es.json @@ -2,19 +2,27 @@ "Categories": { "origami": { "title": "Creaciones de Origami", - "description": "Piezas de arte de plegado de papel intrincadas que muestran precisión y creatividad" + "description": "Piezas de arte de plegado de papel intrincadas que muestran precisión y creatividad", + "gallery": "Galería de creaciones de origami", + "artwork": "Obra de origami" }, "crochet": { "title": "Artículos de Ganchillo", - "description": "Piezas de ganchillo hechas a mano que combinan técnicas tradicionales con diseño moderno" + "description": "Piezas de ganchillo hechas a mano que combinan técnicas tradicionales con diseño moderno", + "gallery": "Galería de artículos de ganchillo", + "artwork": "Obra de ganchillo" }, "paintings": { "title": "Pinturas", - "description": "Pinturas originales que exploran varios estilos y técnicas" + "description": "Pinturas originales que exploran varios estilos y técnicas", + "gallery": "Galería de pinturas", + "artwork": "Obra de pintura" }, "fingernails": { "title": "Arte de Uñas", - "description": "Diseños creativos y detallados de arte de uñas" + "description": "Diseños creativos y detallados de arte de uñas", + "gallery": "Galería de arte de uñas", + "artwork": "Obra de arte de uñas" } }, "Artworks": { diff --git a/messages/artworks/nini/ka.json b/messages/artworks/nini/ka.json index d105fe9..2fdb0c1 100644 --- a/messages/artworks/nini/ka.json +++ b/messages/artworks/nini/ka.json @@ -2,19 +2,27 @@ "Categories": { "origami": { "title": "ორიგამის ნამუშევრები", - "description": "რთული ქაღალდის კეცვის ხელოვნების ნაწარმოებები, რომლებიც გამოირჩევა სიზუსტითა და შემოქმედებითობით" + "description": "რთული ქაღალდის კეცვის ხელოვნების ნაწარმოებები, რომლებიც გამოირჩევა სიზუსტითა და შემოქმედებითობით", + "gallery": "ორიგამის გალერეა", + "artwork": "ორიგამის ნამუშევარი" }, "crochet": { "title": "ქსოვის ნაწარმები", - "description": "ხელნაკეთი ქსოვის ნაწარმოები, რომლებიც აერთიანებს ტრადიციულ ტექნიკებს თანამედროვე დიზაინთან" + "description": "ხელნაკეთი ქსოვის ნაწარმოები, რომლებიც აერთიანებს ტრადიციულ ტექნიკებს თანამედროვე დიზაინთან", + "gallery": "ქსოვის გალერეა", + "artwork": "ქსოვის ნაწარმი" }, "paintings": { "title": "ნახატები", - "description": "ორიგინალური ნახატები, რომლებიც იკვლევს სხვადასხვა სტილსა და ტექნიკას" + "description": "ორიგინალური ნახატები, რომლებიც იკვლევს სხვადასხვა სტილსა და ტექნიკას", + "gallery": "ნახატების გალერეა", + "artwork": "ნახატი" }, "fingernails": { "title": "ფრჩხილების ხელოვნება", - "description": "შემოქმედებითი და დეტალური ფრჩხილების დიზაინები" + "description": "შემოქმედებითი და დეტალური ფრჩხილების დიზაინები", + "gallery": "ფრჩხილების ხელოვნების გალერეა", + "artwork": "ფრჩხილების ნამუშევარი" } }, "Artworks": { diff --git a/messages/artworks/nini/ru.json b/messages/artworks/nini/ru.json index aa6f0d1..333f814 100644 --- a/messages/artworks/nini/ru.json +++ b/messages/artworks/nini/ru.json @@ -2,19 +2,27 @@ "Categories": { "origami": { "title": "Оригами", - "description": "Сложные произведения искусства складывания бумаги, демонстрирующие точность и творчество" + "description": "Сложные произведения искусства складывания бумаги, демонстрирующие точность и творчество", + "gallery": "Галерея оригами", + "artwork": "Произведение оригами" }, "crochet": { "title": "Вязаные изделия", - "description": "Изделия ручной работы, сочетающие традиционные техники с современным дизайном" + "description": "Изделия ручной работы, сочетающие традиционные техники с современным дизайном", + "gallery": "Галерея вязаных изделий", + "artwork": "Вязаное изделие" }, "paintings": { "title": "Картины", - "description": "Оригинальные картины, исследующие различные стили и техники" + "description": "Оригинальные картины, исследующие различные стили и техники", + "gallery": "Галерея картин", + "artwork": "Картина" }, "fingernails": { "title": "Дизайн ногтей", - "description": "Креативные и детализированные дизайны для ногтей" + "description": "Креативные и детализированные дизайны для ногтей", + "gallery": "Галерея дизайна ногтей", + "artwork": "Произведение дизайна ногтей" } }, "Artworks": { diff --git a/messages/artworks/nini/tr.json b/messages/artworks/nini/tr.json index 2cb4f31..8e7e63c 100644 --- a/messages/artworks/nini/tr.json +++ b/messages/artworks/nini/tr.json @@ -2,19 +2,27 @@ "Categories": { "origami": { "title": "Origami Kreasyonları", - "description": "Hassasiyet ve yaratıcılığı sergileyen karmaşık kağıt katlama sanat eserleri" + "description": "Hassasiyet ve yaratıcılığı sergileyen karmaşık kağıt katlama sanat eserleri", + "gallery": "Origami kreasyonları galerisi", + "artwork": "Origami eseri" }, "crochet": { "title": "Örgü Ürünleri", - "description": "Geleneksel teknikleri modern tasarımla birleştiren el yapımı örgü parçaları" + "description": "Geleneksel teknikleri modern tasarımla birleştiren el yapımı örgü parçaları", + "gallery": "Örgü ürünleri galerisi", + "artwork": "Örgü eseri" }, "paintings": { "title": "Resimler", - "description": "Çeşitli stil ve teknikleri keşfeden orijinal resimler" + "description": "Çeşitli stil ve teknikleri keşfeden orijinal resimler", + "gallery": "Resim galerisi", + "artwork": "Resim eseri" }, "fingernails": { "title": "Tırnak Sanatı", - "description": "Yaratıcı ve detaylı tırnak sanatı tasarımları" + "description": "Yaratıcı ve detaylı tırnak sanatı tasarımları", + "gallery": "Tırnak sanatı galerisi", + "artwork": "Tırnak sanatı eseri" } }, "Artworks": { diff --git a/messages/ui/de.json b/messages/ui/de.json index 31ae417..e210c93 100644 --- a/messages/ui/de.json +++ b/messages/ui/de.json @@ -34,7 +34,8 @@ "category": "Kategorie", "viewMoreArtworks": "Weitere Kunstwerke ansehen", "shareArtwork": "Kunstwerk teilen", - "categoryArtwork": "{category} Kunstwerk" + "notFoundTitle": "Kunstwerk nicht gefunden", + "notFoundDescription": "Das angeforderte Kunstwerk konnte nicht gefunden werden." }, "Sort": { "title": "Titel", @@ -42,9 +43,6 @@ "sortByTitle": "Nach Titel sortieren", "sortByYear": "Nach Jahr sortieren" }, - "Gallery": { - "categoryGallery": "{category} Galerie" - }, "Theme": { "changeThemeColors": "Theme-Farben ändern", "themeOptions": "Theme-Optionen", diff --git a/messages/ui/en.json b/messages/ui/en.json index 46ce875..c611de2 100644 --- a/messages/ui/en.json +++ b/messages/ui/en.json @@ -34,7 +34,8 @@ "category": "Category", "viewMoreArtworks": "View More Artworks", "shareArtwork": "Share Artwork", - "categoryArtwork": "{category} Artwork" + "notFoundTitle": "Artwork Not Found", + "notFoundDescription": "The requested artwork could not be found." }, "Sort": { "title": "Title", @@ -42,9 +43,6 @@ "sortByTitle": "Sort by title", "sortByYear": "Sort by year" }, - "Gallery": { - "categoryGallery": "{category} gallery" - }, "Theme": { "changeThemeColors": "Change theme colors", "themeOptions": "Theme options", diff --git a/messages/ui/es.json b/messages/ui/es.json index ee7c83f..96c9fe0 100644 --- a/messages/ui/es.json +++ b/messages/ui/es.json @@ -34,7 +34,8 @@ "category": "Categoría", "viewMoreArtworks": "Ver Más Obras", "shareArtwork": "Compartir Obra", - "categoryArtwork": "Obra de {category}" + "notFoundTitle": "Obra no encontrada", + "notFoundDescription": "No se pudo encontrar la obra solicitada." }, "Sort": { "title": "Título", @@ -42,9 +43,6 @@ "sortByTitle": "Ordenar por título", "sortByYear": "Ordenar por año" }, - "Gallery": { - "categoryGallery": "galería de {category}" - }, "Theme": { "changeThemeColors": "Cambiar colores del tema", "themeOptions": "Opciones de tema", diff --git a/messages/ui/ka.json b/messages/ui/ka.json index ba5137e..134a292 100644 --- a/messages/ui/ka.json +++ b/messages/ui/ka.json @@ -34,7 +34,8 @@ "category": "კატეგორია", "viewMoreArtworks": "მეტი ნამუშევრის ნახვა", "shareArtwork": "ნამუშევრის გაზიარება", - "categoryArtwork": "{category} ნამუშევარი" + "notFoundTitle": "ნამუშევარი ვერ მოიძებნა", + "notFoundDescription": "მოთხოვნილი ნამუშევარი ვერ მოიძებნა." }, "Sort": { "title": "სათაური", @@ -42,9 +43,6 @@ "sortByTitle": "დალაგება სათაურით", "sortByYear": "დალაგება წლით" }, - "Gallery": { - "categoryGallery": "{category} გალერეა" - }, "Theme": { "changeThemeColors": "თემის ფერების შეცვლა", "themeOptions": "თემის პარამეტრები", diff --git a/messages/ui/ru.json b/messages/ui/ru.json index 0540a55..fb81892 100644 --- a/messages/ui/ru.json +++ b/messages/ui/ru.json @@ -34,7 +34,8 @@ "category": "Категория", "viewMoreArtworks": "Посмотреть больше произведений", "shareArtwork": "Поделиться произведением", - "categoryArtwork": "Произведение {category}" + "notFoundTitle": "Произведение не найдено", + "notFoundDescription": "Запрашиваемое произведение не найдено." }, "Sort": { "title": "Название", @@ -42,9 +43,6 @@ "sortByTitle": "Сортировать по названию", "sortByYear": "Сортировать по году" }, - "Gallery": { - "categoryGallery": "Галерея {category}" - }, "Theme": { "changeThemeColors": "Изменить цвета темы", "themeOptions": "Настройки темы", diff --git a/messages/ui/tr.json b/messages/ui/tr.json index 884a2c2..01b13de 100644 --- a/messages/ui/tr.json +++ b/messages/ui/tr.json @@ -34,7 +34,8 @@ "category": "Kategori", "viewMoreArtworks": "Daha Fazla Eser Görüntüle", "shareArtwork": "Eseri Paylaş", - "categoryArtwork": "{category} Eseri" + "notFoundTitle": "Eser Bulunamadı", + "notFoundDescription": "İstenen eser bulunamadı." }, "Sort": { "title": "Başlık", @@ -42,9 +43,6 @@ "sortByTitle": "Başlığa göre sırala", "sortByYear": "Yıla göre sırala" }, - "Gallery": { - "categoryGallery": "{category} galerisi" - }, "Theme": { "changeThemeColors": "Tema renklerini değiştir", "themeOptions": "Tema seçenekleri", diff --git a/src/app/[locale]/admin/login/page.tsx b/src/app/[locale]/admin/login/page.tsx index 796929c..47a8999 100644 --- a/src/app/[locale]/admin/login/page.tsx +++ b/src/app/[locale]/admin/login/page.tsx @@ -1,8 +1,8 @@ "use client"; import { useCallback, useEffect, useState } from "react"; -import { useRouter } from "next/navigation"; -import { useTranslations, useLocale } from "next-intl"; +import { useRouter } from "@/i18n/navigation"; +import { useTranslations } from "next-intl"; interface LoginState { step: "email" | "otp"; @@ -17,7 +17,6 @@ interface LoginState { export default function AdminLogin() { const router = useRouter(); - const locale = useLocale(); const t = useTranslations("admin"); const tCommon = useTranslations("Common"); const [state, setState] = useState({ @@ -113,7 +112,7 @@ export default function AdminLogin() { // Redirect to localized admin dashboard setTimeout(() => { - router.push(`/${locale}/admin`); + router.push("/admin"); }, 1000); } else { updateState({ @@ -140,7 +139,7 @@ export default function AdminLogin() { if (state.configLoading) { return ( -
+
@@ -154,7 +153,7 @@ export default function AdminLogin() { } return ( -
+

diff --git a/src/app/[locale]/admin/page.tsx b/src/app/[locale]/admin/page.tsx index ca31c02..ce0ae21 100644 --- a/src/app/[locale]/admin/page.tsx +++ b/src/app/[locale]/admin/page.tsx @@ -1,7 +1,7 @@ "use client"; import { useState, useEffect, useCallback } from "react"; -import { useRouter } from "next/navigation"; +import { useRouter } from "@/i18n/navigation"; import { useTranslations } from "next-intl"; import { PersonalMessage } from "@/types/config"; import { ArtistProfileWithTranslations } from "@/types/admin"; diff --git a/src/app/[locale]/artwork/[id]/page.tsx b/src/app/[locale]/artwork/[id]/page.tsx index b9798bf..e41c721 100644 --- a/src/app/[locale]/artwork/[id]/page.tsx +++ b/src/app/[locale]/artwork/[id]/page.tsx @@ -45,8 +45,8 @@ export async function generateMetadata({ if (!artwork) { return { - title: "Artwork Not Found", - description: "The requested artwork could not be found.", + title: t("ArtworkDetail.notFoundTitle"), + description: t("ArtworkDetail.notFoundDescription"), }; } diff --git a/src/app/page.tsx b/src/app/page.tsx index 02b1f56..562fb82 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,8 +1,9 @@ import { redirect } from "next/navigation"; +import { routing } from "@/i18n/routing"; // Minimal fallback — the next-intl middleware handles root redirect with // accept-language negotiation and cookie detection. This page should // never be reached in normal operation. export default function RootPage() { - redirect("/en"); + redirect(`/${routing.defaultLocale}`); } diff --git a/src/components/ArtworkCard.tsx b/src/components/ArtworkCard.tsx index b9fa78d..7291466 100644 --- a/src/components/ArtworkCard.tsx +++ b/src/components/ArtworkCard.tsx @@ -1,19 +1,18 @@ "use client"; import { Artwork } from "@/types/artwork"; -import Link from "next/link"; -import { useTranslations, useLocale } from "next-intl"; +import { Link } from "@/i18n/navigation"; +import { useTranslations } from "next-intl"; interface ArtworkCardProps { artwork: Artwork; } export default function ArtworkCard({ artwork }: ArtworkCardProps) { - const locale = useLocale(); const t = useTranslations("Artwork"); return ( - +

- {t("ArtworkDetail.categoryArtwork", { - category: t(`Categories.${artwork.category}.title`), - })} + {t(`Categories.${artwork.category}.artwork`)}

diff --git a/src/components/ArtworkGrid.tsx b/src/components/ArtworkGrid.tsx index 44a4687..1bc39a9 100644 --- a/src/components/ArtworkGrid.tsx +++ b/src/components/ArtworkGrid.tsx @@ -6,16 +6,16 @@ import { useTranslations } from "next-intl"; interface ArtworkGridProps { artworks: Artwork[]; - category: string; + categoryId: string; } -export default function ArtworkGrid({ artworks, category }: ArtworkGridProps) { +export default function ArtworkGrid({ artworks, categoryId }: ArtworkGridProps) { const t = useTranslations(); return (
{artworks.map((artwork) => ( diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 47b8dff..239fe42 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -7,9 +7,9 @@ import { UserIcon, ChevronDownIcon, } from "@heroicons/react/24/outline"; -import Link from "next/link"; -import { useRouter, usePathname, useSearchParams } from "next/navigation"; -import { useTranslations, useLocale } from "next-intl"; +import { useSearchParams } from "next/navigation"; +import { Link, useRouter, usePathname } from "@/i18n/navigation"; +import { useTranslations } from "next-intl"; import LanguageSwitcher from "./LanguageSwitcher"; import { useHeaderHeightCSS } from "@/hooks/useHeaderHeight"; @@ -41,7 +41,6 @@ export default function Header({ const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); - const locale = useLocale(); const t = useTranslations(); // Determine if we're in controlled mode (SearchHeader behavior) or autonomous mode (GlobalHeader behavior) @@ -122,17 +121,15 @@ export default function Header({ // Autonomous mode: handle navigation ourselves setInternalLoading(true); try { - // Check if we're on the localized home page - const isOnHomePage = pathname === `/${locale}`; + // Check if we're on the home page + const isOnHomePage = pathname === "/"; if (!isOnHomePage) { - // Navigate to localized home with search + // Navigate to home with search if (trimmedSearch) { - router.push( - `/${locale}?search=${encodeURIComponent(trimmedSearch)}`, - ); + router.push(`/?search=${encodeURIComponent(trimmedSearch)}`); } else { - router.push(`/${locale}`); + router.push("/"); } } else { // If we're on the home page, update search params @@ -142,7 +139,7 @@ export default function Header({ } else { params.delete("search"); } - router.push(`/${locale}?${params.toString()}`); + router.push(`/?${params.toString()}`); } } finally { setInternalLoading(false); @@ -159,7 +156,7 @@ export default function Header({ setAdminEmail(null); setIsUserMenuOpen(false); setIsLoggingOut(false); - router.push(`/${locale}/admin/login`); + router.push("/admin/login"); } }; @@ -196,7 +193,7 @@ export default function Header({ {isUserMenuOpen && (
setIsUserMenuOpen(false)} className="block px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700" > @@ -215,7 +212,7 @@ export default function Header({
) : ( @@ -228,7 +225,7 @@ export default function Header({ {/* Second row: Title and Description */}
- +

{t("Site.name", { artistName: t("Artist.name") })}

diff --git a/src/components/SectionContainer.tsx b/src/components/SectionContainer.tsx index 9081880..e18b937 100644 --- a/src/components/SectionContainer.tsx +++ b/src/components/SectionContainer.tsx @@ -48,7 +48,7 @@ export default function SectionContainer({ section }: SectionContainerProps) { description={section.description} onSort={handleSort} /> - + ); } diff --git a/src/i18n/request.ts b/src/i18n/request.ts index 298863e..da4f34f 100644 --- a/src/i18n/request.ts +++ b/src/i18n/request.ts @@ -7,17 +7,15 @@ import { getTenantId, tenantMessagePath } from "@/lib/tenant"; export default getRequestConfig(async ({ requestLocale }) => { // The locale is resolved by the next-intl middleware from the URL prefix, // locale cookie, or accept-language negotiation. It should always be present. - const requested = await requestLocale; + const locale = await requestLocale; - if (!requested || !routing.locales.includes(requested as (typeof routing.locales)[number])) { + if (!locale || !routing.locales.includes(locale as (typeof routing.locales)[number])) { throw new Error( - `[i18n/request] Invalid or missing locale "${requested}". ` + + `[i18n/request] Invalid or missing locale "${locale}". ` + "The next-intl middleware should have resolved this before reaching here.", ); } - const locale = requested; - // Resolve the tenant from the proxy-injected header. // Falls back to the default tenant during static prerendering. const tenantId = await getTenantId(); diff --git a/src/lib/admin-auth.ts b/src/lib/admin-auth.ts index 7b6781f..0ac7040 100644 --- a/src/lib/admin-auth.ts +++ b/src/lib/admin-auth.ts @@ -54,7 +54,6 @@ const SMTP_CONFIG = { const ADMIN_EMAIL = process.env.ADMIN_EMAIL!; const JWT_SECRET = process.env.JWT_SECRET!; -const SMTP_FROM_NAME = process.env.SMTP_FROM_NAME; // Create nodemailer transporter const transporter = nodemailer.createTransport(SMTP_CONFIG); @@ -92,10 +91,9 @@ export async function sendOTPEmail( try { const emailTranslations = await getEmailTranslations(locale); const localizedSiteName = await getLocalizedSiteName(locale); - const senderName = SMTP_FROM_NAME || localizedSiteName; const mailOptions = { - from: `${senderName} <${SMTP_CONFIG.auth.user}>`, + from: `${localizedSiteName} <${SMTP_CONFIG.auth.user}>`, to: email, subject: emailTranslations.subject, html: ` diff --git a/src/proxy.ts b/src/proxy.ts index 2ae47ef..657c749 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -62,9 +62,8 @@ export function proxy(request: NextRequest) { new URL(`/${locale}/admin/login`, request.url), ); } - return NextResponse.next({ - request: { headers: requestHeaders }, - }); + // Authenticated — fall through to handleI18nRouting so next-intl + // resolves the locale. Without this, requestLocale is undefined. } // Skip locale handling for API routes and static assets (anything with a