mirror of
https://github.com/HugeFrog24/nini-artgallery.git
synced 2026-03-02 00:14:33 +00:00
Localization and AI chat widget
This commit is contained in:
@@ -28,7 +28,6 @@ services:
|
|||||||
- SMTP_PORT=587
|
- SMTP_PORT=587
|
||||||
- SMTP_USER=smtp-user@example.com
|
- SMTP_USER=smtp-user@example.com
|
||||||
- SMTP_PASS=your-smtp-password
|
- SMTP_PASS=your-smtp-password
|
||||||
- SMTP_FROM_NAME="Your Gallery Name"
|
|
||||||
- SMTP_SECURE=false
|
- SMTP_SECURE=false
|
||||||
- SMTP_REQUIRE_TLS=true
|
- SMTP_REQUIRE_TLS=true
|
||||||
- JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
- JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Gemälde & Digitale Kunst",
|
"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": {
|
"origami": {
|
||||||
"title": "Illustrationen",
|
"title": "Illustrationen",
|
||||||
"description": "Handgezeichnete Tuscheillustrationen, inspiriert von Märchen"
|
"description": "Handgezeichnete Tuscheillustrationen, inspiriert von Märchen",
|
||||||
|
"gallery": "Illustrationen-Galerie",
|
||||||
|
"artwork": "Illustration"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Artworks": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Paintings & Digital Art",
|
"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": {
|
"origami": {
|
||||||
"title": "Illustrations",
|
"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": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Pinturas y Arte Digital",
|
"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": {
|
"origami": {
|
||||||
"title": "Ilustraciones",
|
"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": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "ნახატები და ციფრული ხელოვნება",
|
"title": "ნახატები და ციფრული ხელოვნება",
|
||||||
"description": "ოცნებისებური ნახატები, რომლებიც ფანტაზიასა და ემოციას აერთიანებს"
|
"description": "ოცნებისებური ნახატები, რომლებიც ფანტაზიასა და ემოციას აერთიანებს",
|
||||||
|
"gallery": "ნახატებისა და ციფრული ხელოვნების გალერეა",
|
||||||
|
"artwork": "ნახატი"
|
||||||
},
|
},
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "ილუსტრაციები",
|
"title": "ილუსტრაციები",
|
||||||
"description": "ხელით დახატული და მელნის ილუსტრაციები, ზღაპრებით შთაგონებული"
|
"description": "ხელით დახატული და მელნის ილუსტრაციები, ზღაპრებით შთაგონებული",
|
||||||
|
"gallery": "ილუსტრაციების გალერეა",
|
||||||
|
"artwork": "ილუსტრაცია"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Artworks": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Картины и цифровое искусство",
|
"title": "Картины и цифровое искусство",
|
||||||
"description": "Мечтательные картины, сочетающие фантазию и эмоции"
|
"description": "Мечтательные картины, сочетающие фантазию и эмоции",
|
||||||
|
"gallery": "Галерея картин и цифрового искусства",
|
||||||
|
"artwork": "Картина"
|
||||||
},
|
},
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "Иллюстрации",
|
"title": "Иллюстрации",
|
||||||
"description": "Рисунки тушью и акварелью, вдохновлённые сказками"
|
"description": "Рисунки тушью и акварелью, вдохновлённые сказками",
|
||||||
|
"gallery": "Галерея иллюстраций",
|
||||||
|
"artwork": "Иллюстрация"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Artworks": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Tablolar ve Dijital Sanat",
|
"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": {
|
"origami": {
|
||||||
"title": "İllüstrasyonlar",
|
"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": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,19 +2,27 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "Origami-Kreationen",
|
"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": {
|
"crochet": {
|
||||||
"title": "Häkelarbeiten",
|
"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": {
|
"paintings": {
|
||||||
"title": "Gemälde",
|
"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": {
|
"fingernails": {
|
||||||
"title": "Nagelkunst",
|
"title": "Nagelkunst",
|
||||||
"description": "Kreative und detaillierte Nagelkunst-Designs"
|
"description": "Kreative und detaillierte Nagelkunst-Designs",
|
||||||
|
"gallery": "Nagelkunst-Galerie",
|
||||||
|
"artwork": "Nagelkunst-Werk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Artworks": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,19 +2,27 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "Origami Creations",
|
"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": {
|
"crochet": {
|
||||||
"title": "Crochet Items",
|
"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": {
|
"paintings": {
|
||||||
"title": "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": {
|
"fingernails": {
|
||||||
"title": "Fingernail Art",
|
"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": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,19 +2,27 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "Creaciones de 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": {
|
"crochet": {
|
||||||
"title": "Artículos de Ganchillo",
|
"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": {
|
"paintings": {
|
||||||
"title": "Pinturas",
|
"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": {
|
"fingernails": {
|
||||||
"title": "Arte de Uñas",
|
"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": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,19 +2,27 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "ორიგამის ნამუშევრები",
|
"title": "ორიგამის ნამუშევრები",
|
||||||
"description": "რთული ქაღალდის კეცვის ხელოვნების ნაწარმოებები, რომლებიც გამოირჩევა სიზუსტითა და შემოქმედებითობით"
|
"description": "რთული ქაღალდის კეცვის ხელოვნების ნაწარმოებები, რომლებიც გამოირჩევა სიზუსტითა და შემოქმედებითობით",
|
||||||
|
"gallery": "ორიგამის გალერეა",
|
||||||
|
"artwork": "ორიგამის ნამუშევარი"
|
||||||
},
|
},
|
||||||
"crochet": {
|
"crochet": {
|
||||||
"title": "ქსოვის ნაწარმები",
|
"title": "ქსოვის ნაწარმები",
|
||||||
"description": "ხელნაკეთი ქსოვის ნაწარმოები, რომლებიც აერთიანებს ტრადიციულ ტექნიკებს თანამედროვე დიზაინთან"
|
"description": "ხელნაკეთი ქსოვის ნაწარმოები, რომლებიც აერთიანებს ტრადიციულ ტექნიკებს თანამედროვე დიზაინთან",
|
||||||
|
"gallery": "ქსოვის გალერეა",
|
||||||
|
"artwork": "ქსოვის ნაწარმი"
|
||||||
},
|
},
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "ნახატები",
|
"title": "ნახატები",
|
||||||
"description": "ორიგინალური ნახატები, რომლებიც იკვლევს სხვადასხვა სტილსა და ტექნიკას"
|
"description": "ორიგინალური ნახატები, რომლებიც იკვლევს სხვადასხვა სტილსა და ტექნიკას",
|
||||||
|
"gallery": "ნახატების გალერეა",
|
||||||
|
"artwork": "ნახატი"
|
||||||
},
|
},
|
||||||
"fingernails": {
|
"fingernails": {
|
||||||
"title": "ფრჩხილების ხელოვნება",
|
"title": "ფრჩხილების ხელოვნება",
|
||||||
"description": "შემოქმედებითი და დეტალური ფრჩხილების დიზაინები"
|
"description": "შემოქმედებითი და დეტალური ფრჩხილების დიზაინები",
|
||||||
|
"gallery": "ფრჩხილების ხელოვნების გალერეა",
|
||||||
|
"artwork": "ფრჩხილების ნამუშევარი"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Artworks": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,19 +2,27 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "Оригами",
|
"title": "Оригами",
|
||||||
"description": "Сложные произведения искусства складывания бумаги, демонстрирующие точность и творчество"
|
"description": "Сложные произведения искусства складывания бумаги, демонстрирующие точность и творчество",
|
||||||
|
"gallery": "Галерея оригами",
|
||||||
|
"artwork": "Произведение оригами"
|
||||||
},
|
},
|
||||||
"crochet": {
|
"crochet": {
|
||||||
"title": "Вязаные изделия",
|
"title": "Вязаные изделия",
|
||||||
"description": "Изделия ручной работы, сочетающие традиционные техники с современным дизайном"
|
"description": "Изделия ручной работы, сочетающие традиционные техники с современным дизайном",
|
||||||
|
"gallery": "Галерея вязаных изделий",
|
||||||
|
"artwork": "Вязаное изделие"
|
||||||
},
|
},
|
||||||
"paintings": {
|
"paintings": {
|
||||||
"title": "Картины",
|
"title": "Картины",
|
||||||
"description": "Оригинальные картины, исследующие различные стили и техники"
|
"description": "Оригинальные картины, исследующие различные стили и техники",
|
||||||
|
"gallery": "Галерея картин",
|
||||||
|
"artwork": "Картина"
|
||||||
},
|
},
|
||||||
"fingernails": {
|
"fingernails": {
|
||||||
"title": "Дизайн ногтей",
|
"title": "Дизайн ногтей",
|
||||||
"description": "Креативные и детализированные дизайны для ногтей"
|
"description": "Креативные и детализированные дизайны для ногтей",
|
||||||
|
"gallery": "Галерея дизайна ногтей",
|
||||||
|
"artwork": "Произведение дизайна ногтей"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Artworks": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -2,19 +2,27 @@
|
|||||||
"Categories": {
|
"Categories": {
|
||||||
"origami": {
|
"origami": {
|
||||||
"title": "Origami Kreasyonları",
|
"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": {
|
"crochet": {
|
||||||
"title": "Örgü Ürünleri",
|
"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": {
|
"paintings": {
|
||||||
"title": "Resimler",
|
"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": {
|
"fingernails": {
|
||||||
"title": "Tırnak Sanatı",
|
"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": {
|
"Artworks": {
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
"category": "Kategorie",
|
"category": "Kategorie",
|
||||||
"viewMoreArtworks": "Weitere Kunstwerke ansehen",
|
"viewMoreArtworks": "Weitere Kunstwerke ansehen",
|
||||||
"shareArtwork": "Kunstwerk teilen",
|
"shareArtwork": "Kunstwerk teilen",
|
||||||
"categoryArtwork": "{category} Kunstwerk"
|
"notFoundTitle": "Kunstwerk nicht gefunden",
|
||||||
|
"notFoundDescription": "Das angeforderte Kunstwerk konnte nicht gefunden werden."
|
||||||
},
|
},
|
||||||
"Sort": {
|
"Sort": {
|
||||||
"title": "Titel",
|
"title": "Titel",
|
||||||
@@ -42,9 +43,6 @@
|
|||||||
"sortByTitle": "Nach Titel sortieren",
|
"sortByTitle": "Nach Titel sortieren",
|
||||||
"sortByYear": "Nach Jahr sortieren"
|
"sortByYear": "Nach Jahr sortieren"
|
||||||
},
|
},
|
||||||
"Gallery": {
|
|
||||||
"categoryGallery": "{category} Galerie"
|
|
||||||
},
|
|
||||||
"Theme": {
|
"Theme": {
|
||||||
"changeThemeColors": "Theme-Farben ändern",
|
"changeThemeColors": "Theme-Farben ändern",
|
||||||
"themeOptions": "Theme-Optionen",
|
"themeOptions": "Theme-Optionen",
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
"category": "Category",
|
"category": "Category",
|
||||||
"viewMoreArtworks": "View More Artworks",
|
"viewMoreArtworks": "View More Artworks",
|
||||||
"shareArtwork": "Share Artwork",
|
"shareArtwork": "Share Artwork",
|
||||||
"categoryArtwork": "{category} Artwork"
|
"notFoundTitle": "Artwork Not Found",
|
||||||
|
"notFoundDescription": "The requested artwork could not be found."
|
||||||
},
|
},
|
||||||
"Sort": {
|
"Sort": {
|
||||||
"title": "Title",
|
"title": "Title",
|
||||||
@@ -42,9 +43,6 @@
|
|||||||
"sortByTitle": "Sort by title",
|
"sortByTitle": "Sort by title",
|
||||||
"sortByYear": "Sort by year"
|
"sortByYear": "Sort by year"
|
||||||
},
|
},
|
||||||
"Gallery": {
|
|
||||||
"categoryGallery": "{category} gallery"
|
|
||||||
},
|
|
||||||
"Theme": {
|
"Theme": {
|
||||||
"changeThemeColors": "Change theme colors",
|
"changeThemeColors": "Change theme colors",
|
||||||
"themeOptions": "Theme options",
|
"themeOptions": "Theme options",
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
"category": "Categoría",
|
"category": "Categoría",
|
||||||
"viewMoreArtworks": "Ver Más Obras",
|
"viewMoreArtworks": "Ver Más Obras",
|
||||||
"shareArtwork": "Compartir Obra",
|
"shareArtwork": "Compartir Obra",
|
||||||
"categoryArtwork": "Obra de {category}"
|
"notFoundTitle": "Obra no encontrada",
|
||||||
|
"notFoundDescription": "No se pudo encontrar la obra solicitada."
|
||||||
},
|
},
|
||||||
"Sort": {
|
"Sort": {
|
||||||
"title": "Título",
|
"title": "Título",
|
||||||
@@ -42,9 +43,6 @@
|
|||||||
"sortByTitle": "Ordenar por título",
|
"sortByTitle": "Ordenar por título",
|
||||||
"sortByYear": "Ordenar por año"
|
"sortByYear": "Ordenar por año"
|
||||||
},
|
},
|
||||||
"Gallery": {
|
|
||||||
"categoryGallery": "galería de {category}"
|
|
||||||
},
|
|
||||||
"Theme": {
|
"Theme": {
|
||||||
"changeThemeColors": "Cambiar colores del tema",
|
"changeThemeColors": "Cambiar colores del tema",
|
||||||
"themeOptions": "Opciones de tema",
|
"themeOptions": "Opciones de tema",
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
"category": "კატეგორია",
|
"category": "კატეგორია",
|
||||||
"viewMoreArtworks": "მეტი ნამუშევრის ნახვა",
|
"viewMoreArtworks": "მეტი ნამუშევრის ნახვა",
|
||||||
"shareArtwork": "ნამუშევრის გაზიარება",
|
"shareArtwork": "ნამუშევრის გაზიარება",
|
||||||
"categoryArtwork": "{category} ნამუშევარი"
|
"notFoundTitle": "ნამუშევარი ვერ მოიძებნა",
|
||||||
|
"notFoundDescription": "მოთხოვნილი ნამუშევარი ვერ მოიძებნა."
|
||||||
},
|
},
|
||||||
"Sort": {
|
"Sort": {
|
||||||
"title": "სათაური",
|
"title": "სათაური",
|
||||||
@@ -42,9 +43,6 @@
|
|||||||
"sortByTitle": "დალაგება სათაურით",
|
"sortByTitle": "დალაგება სათაურით",
|
||||||
"sortByYear": "დალაგება წლით"
|
"sortByYear": "დალაგება წლით"
|
||||||
},
|
},
|
||||||
"Gallery": {
|
|
||||||
"categoryGallery": "{category} გალერეა"
|
|
||||||
},
|
|
||||||
"Theme": {
|
"Theme": {
|
||||||
"changeThemeColors": "თემის ფერების შეცვლა",
|
"changeThemeColors": "თემის ფერების შეცვლა",
|
||||||
"themeOptions": "თემის პარამეტრები",
|
"themeOptions": "თემის პარამეტრები",
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
"category": "Категория",
|
"category": "Категория",
|
||||||
"viewMoreArtworks": "Посмотреть больше произведений",
|
"viewMoreArtworks": "Посмотреть больше произведений",
|
||||||
"shareArtwork": "Поделиться произведением",
|
"shareArtwork": "Поделиться произведением",
|
||||||
"categoryArtwork": "Произведение {category}"
|
"notFoundTitle": "Произведение не найдено",
|
||||||
|
"notFoundDescription": "Запрашиваемое произведение не найдено."
|
||||||
},
|
},
|
||||||
"Sort": {
|
"Sort": {
|
||||||
"title": "Название",
|
"title": "Название",
|
||||||
@@ -42,9 +43,6 @@
|
|||||||
"sortByTitle": "Сортировать по названию",
|
"sortByTitle": "Сортировать по названию",
|
||||||
"sortByYear": "Сортировать по году"
|
"sortByYear": "Сортировать по году"
|
||||||
},
|
},
|
||||||
"Gallery": {
|
|
||||||
"categoryGallery": "Галерея {category}"
|
|
||||||
},
|
|
||||||
"Theme": {
|
"Theme": {
|
||||||
"changeThemeColors": "Изменить цвета темы",
|
"changeThemeColors": "Изменить цвета темы",
|
||||||
"themeOptions": "Настройки темы",
|
"themeOptions": "Настройки темы",
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
"category": "Kategori",
|
"category": "Kategori",
|
||||||
"viewMoreArtworks": "Daha Fazla Eser Görüntüle",
|
"viewMoreArtworks": "Daha Fazla Eser Görüntüle",
|
||||||
"shareArtwork": "Eseri Paylaş",
|
"shareArtwork": "Eseri Paylaş",
|
||||||
"categoryArtwork": "{category} Eseri"
|
"notFoundTitle": "Eser Bulunamadı",
|
||||||
|
"notFoundDescription": "İstenen eser bulunamadı."
|
||||||
},
|
},
|
||||||
"Sort": {
|
"Sort": {
|
||||||
"title": "Başlık",
|
"title": "Başlık",
|
||||||
@@ -42,9 +43,6 @@
|
|||||||
"sortByTitle": "Başlığa göre sırala",
|
"sortByTitle": "Başlığa göre sırala",
|
||||||
"sortByYear": "Yıla göre sırala"
|
"sortByYear": "Yıla göre sırala"
|
||||||
},
|
},
|
||||||
"Gallery": {
|
|
||||||
"categoryGallery": "{category} galerisi"
|
|
||||||
},
|
|
||||||
"Theme": {
|
"Theme": {
|
||||||
"changeThemeColors": "Tema renklerini değiştir",
|
"changeThemeColors": "Tema renklerini değiştir",
|
||||||
"themeOptions": "Tema seçenekleri",
|
"themeOptions": "Tema seçenekleri",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "@/i18n/navigation";
|
||||||
import { useTranslations, useLocale } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
interface LoginState {
|
interface LoginState {
|
||||||
step: "email" | "otp";
|
step: "email" | "otp";
|
||||||
@@ -17,7 +17,6 @@ interface LoginState {
|
|||||||
|
|
||||||
export default function AdminLogin() {
|
export default function AdminLogin() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const locale = useLocale();
|
|
||||||
const t = useTranslations("admin");
|
const t = useTranslations("admin");
|
||||||
const tCommon = useTranslations("Common");
|
const tCommon = useTranslations("Common");
|
||||||
const [state, setState] = useState<LoginState>({
|
const [state, setState] = useState<LoginState>({
|
||||||
@@ -113,7 +112,7 @@ export default function AdminLogin() {
|
|||||||
|
|
||||||
// Redirect to localized admin dashboard
|
// Redirect to localized admin dashboard
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push(`/${locale}/admin`);
|
router.push("/admin");
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
updateState({
|
updateState({
|
||||||
@@ -140,7 +139,7 @@ export default function AdminLogin() {
|
|||||||
|
|
||||||
if (state.configLoading) {
|
if (state.configLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
<div className="min-h-[calc(100vh-var(--header-height,160px))] flex items-center justify-center px-4 sm:px-6 lg:px-8">
|
||||||
<div className="max-w-md w-full space-y-8">
|
<div className="max-w-md w-full space-y-8">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-accent-600 mx-auto"></div>
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-accent-600 mx-auto"></div>
|
||||||
@@ -154,7 +153,7 @@ export default function AdminLogin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
<div className="min-h-[calc(100vh-var(--header-height,160px))] flex items-center justify-center px-4 sm:px-6 lg:px-8">
|
||||||
<div className="max-w-md w-full space-y-8">
|
<div className="max-w-md w-full space-y-8">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900 dark:text-white">
|
<h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900 dark:text-white">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "@/i18n/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { PersonalMessage } from "@/types/config";
|
import { PersonalMessage } from "@/types/config";
|
||||||
import { ArtistProfileWithTranslations } from "@/types/admin";
|
import { ArtistProfileWithTranslations } from "@/types/admin";
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ export async function generateMetadata({
|
|||||||
|
|
||||||
if (!artwork) {
|
if (!artwork) {
|
||||||
return {
|
return {
|
||||||
title: "Artwork Not Found",
|
title: t("ArtworkDetail.notFoundTitle"),
|
||||||
description: "The requested artwork could not be found.",
|
description: t("ArtworkDetail.notFoundDescription"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
import { routing } from "@/i18n/routing";
|
||||||
|
|
||||||
// Minimal fallback — the next-intl middleware handles root redirect with
|
// Minimal fallback — the next-intl middleware handles root redirect with
|
||||||
// accept-language negotiation and cookie detection. This page should
|
// accept-language negotiation and cookie detection. This page should
|
||||||
// never be reached in normal operation.
|
// never be reached in normal operation.
|
||||||
export default function RootPage() {
|
export default function RootPage() {
|
||||||
redirect("/en");
|
redirect(`/${routing.defaultLocale}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Artwork } from "@/types/artwork";
|
import { Artwork } from "@/types/artwork";
|
||||||
import Link from "next/link";
|
import { Link } from "@/i18n/navigation";
|
||||||
import { useTranslations, useLocale } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
interface ArtworkCardProps {
|
interface ArtworkCardProps {
|
||||||
artwork: Artwork;
|
artwork: Artwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ArtworkCard({ artwork }: ArtworkCardProps) {
|
export default function ArtworkCard({ artwork }: ArtworkCardProps) {
|
||||||
const locale = useLocale();
|
|
||||||
const t = useTranslations("Artwork");
|
const t = useTranslations("Artwork");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/${locale}/artwork/${artwork.id}`} className="block w-full">
|
<Link href={`/artwork/${artwork.id}`} className="block w-full">
|
||||||
<article
|
<article
|
||||||
className="group relative bg-white dark:bg-gray-800 rounded-md overflow-hidden shadow-sm transition-all duration-300 hover:shadow-md hover:-translate-y-0.5 w-full cursor-pointer"
|
className="group relative bg-white dark:bg-gray-800 rounded-md overflow-hidden shadow-sm transition-all duration-300 hover:shadow-md hover:-translate-y-0.5 w-full cursor-pointer"
|
||||||
aria-labelledby={`title-${artwork.id}`}
|
aria-labelledby={`title-${artwork.id}`}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Artwork } from "@/types/artwork";
|
import { Artwork } from "@/types/artwork";
|
||||||
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
|
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "@/i18n/navigation";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
interface ArtworkDetailViewProps {
|
interface ArtworkDetailViewProps {
|
||||||
@@ -47,9 +47,7 @@ export default function ArtworkDetailView({ artwork }: ArtworkDetailViewProps) {
|
|||||||
{/* Image caption */}
|
{/* Image caption */}
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
{t("ArtworkDetail.categoryArtwork", {
|
{t(`Categories.${artwork.category}.artwork`)}
|
||||||
category: t(`Categories.${artwork.category}.title`),
|
|
||||||
})}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,16 +6,16 @@ import { useTranslations } from "next-intl";
|
|||||||
|
|
||||||
interface ArtworkGridProps {
|
interface ArtworkGridProps {
|
||||||
artworks: Artwork[];
|
artworks: Artwork[];
|
||||||
category: string;
|
categoryId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ArtworkGrid({ artworks, category }: ArtworkGridProps) {
|
export default function ArtworkGrid({ artworks, categoryId }: ArtworkGridProps) {
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8 gap-2"
|
className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8 gap-2"
|
||||||
aria-label={t("Gallery.categoryGallery", { category })}
|
aria-label={t(`Categories.${categoryId}.gallery`)}
|
||||||
>
|
>
|
||||||
{artworks.map((artwork) => (
|
{artworks.map((artwork) => (
|
||||||
<ArtworkCard key={artwork.id} artwork={artwork} />
|
<ArtworkCard key={artwork.id} artwork={artwork} />
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import {
|
|||||||
UserIcon,
|
UserIcon,
|
||||||
ChevronDownIcon,
|
ChevronDownIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
import Link from "next/link";
|
import { useSearchParams } from "next/navigation";
|
||||||
import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
import { Link, useRouter, usePathname } from "@/i18n/navigation";
|
||||||
import { useTranslations, useLocale } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import LanguageSwitcher from "./LanguageSwitcher";
|
import LanguageSwitcher from "./LanguageSwitcher";
|
||||||
import { useHeaderHeightCSS } from "@/hooks/useHeaderHeight";
|
import { useHeaderHeightCSS } from "@/hooks/useHeaderHeight";
|
||||||
|
|
||||||
@@ -41,7 +41,6 @@ export default function Header({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const locale = useLocale();
|
|
||||||
const t = useTranslations();
|
const t = useTranslations();
|
||||||
|
|
||||||
// Determine if we're in controlled mode (SearchHeader behavior) or autonomous mode (GlobalHeader behavior)
|
// 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
|
// Autonomous mode: handle navigation ourselves
|
||||||
setInternalLoading(true);
|
setInternalLoading(true);
|
||||||
try {
|
try {
|
||||||
// Check if we're on the localized home page
|
// Check if we're on the home page
|
||||||
const isOnHomePage = pathname === `/${locale}`;
|
const isOnHomePage = pathname === "/";
|
||||||
|
|
||||||
if (!isOnHomePage) {
|
if (!isOnHomePage) {
|
||||||
// Navigate to localized home with search
|
// Navigate to home with search
|
||||||
if (trimmedSearch) {
|
if (trimmedSearch) {
|
||||||
router.push(
|
router.push(`/?search=${encodeURIComponent(trimmedSearch)}`);
|
||||||
`/${locale}?search=${encodeURIComponent(trimmedSearch)}`,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
router.push(`/${locale}`);
|
router.push("/");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we're on the home page, update search params
|
// If we're on the home page, update search params
|
||||||
@@ -142,7 +139,7 @@ export default function Header({
|
|||||||
} else {
|
} else {
|
||||||
params.delete("search");
|
params.delete("search");
|
||||||
}
|
}
|
||||||
router.push(`/${locale}?${params.toString()}`);
|
router.push(`/?${params.toString()}`);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setInternalLoading(false);
|
setInternalLoading(false);
|
||||||
@@ -159,7 +156,7 @@ export default function Header({
|
|||||||
setAdminEmail(null);
|
setAdminEmail(null);
|
||||||
setIsUserMenuOpen(false);
|
setIsUserMenuOpen(false);
|
||||||
setIsLoggingOut(false);
|
setIsLoggingOut(false);
|
||||||
router.push(`/${locale}/admin/login`);
|
router.push("/admin/login");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -196,7 +193,7 @@ export default function Header({
|
|||||||
{isUserMenuOpen && (
|
{isUserMenuOpen && (
|
||||||
<div className="absolute right-0 mt-2 w-48 rounded-md border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-lg py-1 z-50">
|
<div className="absolute right-0 mt-2 w-48 rounded-md border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow-lg py-1 z-50">
|
||||||
<Link
|
<Link
|
||||||
href={`/${locale}/admin`}
|
href="/admin"
|
||||||
onClick={() => setIsUserMenuOpen(false)}
|
onClick={() => 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"
|
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({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
href={`/${locale}/admin/login`}
|
href="/admin/login"
|
||||||
className="inline-flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-accent-600 dark:hover:text-accent-400 transition-colors"
|
className="inline-flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 hover:text-accent-600 dark:hover:text-accent-400 transition-colors"
|
||||||
>
|
>
|
||||||
<UserIcon className="h-4 w-4" />
|
<UserIcon className="h-4 w-4" />
|
||||||
@@ -228,7 +225,7 @@ export default function Header({
|
|||||||
|
|
||||||
{/* Second row: Title and Description */}
|
{/* Second row: Title and Description */}
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<Link href={`/${locale}`} className="inline-block">
|
<Link href="/" className="inline-block">
|
||||||
<h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-1 hover:text-accent-600 transition-colors">
|
<h1 className="text-2xl font-bold text-gray-900 dark:text-white mb-1 hover:text-accent-600 transition-colors">
|
||||||
{t("Site.name", { artistName: t("Artist.name") })}
|
{t("Site.name", { artistName: t("Artist.name") })}
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export default function SectionContainer({ section }: SectionContainerProps) {
|
|||||||
description={section.description}
|
description={section.description}
|
||||||
onSort={handleSort}
|
onSort={handleSort}
|
||||||
/>
|
/>
|
||||||
<ArtworkGrid artworks={sortedArtworks} category={section.title} />
|
<ArtworkGrid artworks={sortedArtworks} categoryId={section.id} />
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,15 @@ import { getTenantId, tenantMessagePath } from "@/lib/tenant";
|
|||||||
export default getRequestConfig(async ({ requestLocale }) => {
|
export default getRequestConfig(async ({ requestLocale }) => {
|
||||||
// The locale is resolved by the next-intl middleware from the URL prefix,
|
// The locale is resolved by the next-intl middleware from the URL prefix,
|
||||||
// locale cookie, or accept-language negotiation. It should always be present.
|
// 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(
|
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.",
|
"The next-intl middleware should have resolved this before reaching here.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const locale = requested;
|
|
||||||
|
|
||||||
// Resolve the tenant from the proxy-injected header.
|
// Resolve the tenant from the proxy-injected header.
|
||||||
// Falls back to the default tenant during static prerendering.
|
// Falls back to the default tenant during static prerendering.
|
||||||
const tenantId = await getTenantId();
|
const tenantId = await getTenantId();
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ const SMTP_CONFIG = {
|
|||||||
|
|
||||||
const ADMIN_EMAIL = process.env.ADMIN_EMAIL!;
|
const ADMIN_EMAIL = process.env.ADMIN_EMAIL!;
|
||||||
const JWT_SECRET = process.env.JWT_SECRET!;
|
const JWT_SECRET = process.env.JWT_SECRET!;
|
||||||
const SMTP_FROM_NAME = process.env.SMTP_FROM_NAME;
|
|
||||||
|
|
||||||
// Create nodemailer transporter
|
// Create nodemailer transporter
|
||||||
const transporter = nodemailer.createTransport(SMTP_CONFIG);
|
const transporter = nodemailer.createTransport(SMTP_CONFIG);
|
||||||
@@ -92,10 +91,9 @@ export async function sendOTPEmail(
|
|||||||
try {
|
try {
|
||||||
const emailTranslations = await getEmailTranslations(locale);
|
const emailTranslations = await getEmailTranslations(locale);
|
||||||
const localizedSiteName = await getLocalizedSiteName(locale);
|
const localizedSiteName = await getLocalizedSiteName(locale);
|
||||||
const senderName = SMTP_FROM_NAME || localizedSiteName;
|
|
||||||
|
|
||||||
const mailOptions = {
|
const mailOptions = {
|
||||||
from: `${senderName} <${SMTP_CONFIG.auth.user}>`,
|
from: `${localizedSiteName} <${SMTP_CONFIG.auth.user}>`,
|
||||||
to: email,
|
to: email,
|
||||||
subject: emailTranslations.subject,
|
subject: emailTranslations.subject,
|
||||||
html: `
|
html: `
|
||||||
|
|||||||
@@ -62,9 +62,8 @@ export function proxy(request: NextRequest) {
|
|||||||
new URL(`/${locale}/admin/login`, request.url),
|
new URL(`/${locale}/admin/login`, request.url),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return NextResponse.next({
|
// Authenticated — fall through to handleI18nRouting so next-intl
|
||||||
request: { headers: requestHeaders },
|
// resolves the locale. Without this, requestLocale is undefined.
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip locale handling for API routes and static assets (anything with a
|
// Skip locale handling for API routes and static assets (anything with a
|
||||||
|
|||||||
Reference in New Issue
Block a user