diff --git a/Makefile b/Makefile index b9f50c6..c31e795 100644 --- a/Makefile +++ b/Makefile @@ -35,4 +35,7 @@ clean: docker image prune -f ui: - $(COMPOSE) exec $(SERVICE_NAME) npx shadcn@latest add $(component) \ No newline at end of file + $(COMPOSE) exec $(SERVICE_NAME) npx shadcn@latest add $(component) + +i: + $(COMPOSE) exec $(SERVICE_NAME) npm install $(package) \ No newline at end of file diff --git a/app/(backend)/users/page.tsx b/app/(backend)/users/page.tsx deleted file mode 100644 index ed4d1fe..0000000 --- a/app/(backend)/users/page.tsx +++ /dev/null @@ -1,129 +0,0 @@ -'use client'; - -import { useState } from "react"; -import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; -import { Search, Plus, MoreVertical, Filter } from "lucide-react"; -import { UserMobileCard } from "./components/UserMobileCard"; -import { UserFormWrapper } from "./components/UserFormWrapper"; - -// Temporary user data for demonstration -const tempUsers = [ - { id: 1, name: "John Doe", email: "john@example.com", role: "Admin", joinedAt: "2023-01-01", status: "active" }, - { id: 2, name: "Alice Smith", email: "alice@test.com", role: "Editor", joinedAt: "2023-02-15", status: "active" }, - { id: 3, name: "Bob Johnson", email: "bob@community.com", role: "Member", joinedAt: "2023-03-10", status: "inactive" }, - { id: 4, name: "Charlie Brown", email: "charlie@community.com", role: "Member", joinedAt: "2023-04-20", status: "active" }, -]; - -export default function UsersPage() { - - const [open, setOpen] = useState(false) - - return ( -
-
- - {/* Header: Title + Button for Desktop only */} -
-
-

- Users -

-

- Manage your community members, roles, and permissions here. -

-
- - {/* Button: Add New User for Desktop only */} - -
- - {/* Search + Filter */} -
-
- - -
- -
-
- {/* Button: Add New User for Mobile only */} -
- -
-
-
- - {/* --- For Mobile Phones --- */} -
- {tempUsers.map((user) => ( - - ))} -
- - {/* Users List / Table */} -
- - - - - - - - - - - - {/* Example Row */} - {tempUsers.map((user) => ( - - - - - - - - ))} - -
UserRoleStatusJoined
-
-
{user.name.charAt(0)}
-
-
{user.name}
-
{user.email}
-
-
-
- {user.role} - - - {user.status} - - {user.joinedAt} - -
-
-
- ); -} \ No newline at end of file diff --git a/app/(backend)/admin/page.tsx b/app/[locale]/(backend)/admin/page.tsx similarity index 100% rename from app/(backend)/admin/page.tsx rename to app/[locale]/(backend)/admin/page.tsx diff --git a/app/(backend)/layout.tsx b/app/[locale]/(backend)/layout.tsx similarity index 100% rename from app/(backend)/layout.tsx rename to app/[locale]/(backend)/layout.tsx diff --git a/app/(backend)/page.tsx b/app/[locale]/(backend)/page.tsx similarity index 97% rename from app/(backend)/page.tsx rename to app/[locale]/(backend)/page.tsx index 5ed737d..1029ffb 100644 --- a/app/(backend)/page.tsx +++ b/app/[locale]/(backend)/page.tsx @@ -21,10 +21,12 @@ import { UserCircle, Users, } from "lucide-react"; +import { useTranslations } from "next-intl"; import Link from "next/link"; import React from "react"; const Dashboard: React.FC = () => { + const t = useTranslations("dashboard"); const categories: ModuleCategory[] = [ { title: "People & Community", @@ -170,11 +172,9 @@ const Dashboard: React.FC = () => {

- Community Dashboard + {t("title")}

-

- Welcome to the admin area. Manage your community resources safely. -

+

{t("welcome")}

diff --git a/app/(backend)/users/components/UserForm/index.tsx b/app/[locale]/(backend)/users/components/UserForm/index.tsx similarity index 100% rename from app/(backend)/users/components/UserForm/index.tsx rename to app/[locale]/(backend)/users/components/UserForm/index.tsx diff --git a/app/(backend)/users/components/UserFormWrapper.tsx b/app/[locale]/(backend)/users/components/UserFormWrapper.tsx similarity index 100% rename from app/(backend)/users/components/UserFormWrapper.tsx rename to app/[locale]/(backend)/users/components/UserFormWrapper.tsx diff --git a/app/(backend)/users/components/UserMobileCard/index.tsx b/app/[locale]/(backend)/users/components/UserMobileCard/index.tsx similarity index 100% rename from app/(backend)/users/components/UserMobileCard/index.tsx rename to app/[locale]/(backend)/users/components/UserMobileCard/index.tsx diff --git a/app/[locale]/(backend)/users/page.tsx b/app/[locale]/(backend)/users/page.tsx new file mode 100644 index 0000000..97c455e --- /dev/null +++ b/app/[locale]/(backend)/users/page.tsx @@ -0,0 +1,185 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Filter, MoreVertical, Search } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { useState } from "react"; +import { UserFormWrapper } from "./components/UserFormWrapper"; +import { UserMobileCard } from "./components/UserMobileCard"; + +// Temporary user data for demonstration +const tempUsers = [ + { + id: 1, + name: "John Doe", + email: "john@example.com", + role: "Admin", + joinedAt: "2023-01-01", + status: "active", + }, + { + id: 2, + name: "Alice Smith", + email: "alice@test.com", + role: "Editor", + joinedAt: "2023-02-15", + status: "active", + }, + { + id: 3, + name: "Bob Johnson", + email: "bob@community.com", + role: "Member", + joinedAt: "2023-03-10", + status: "inactive", + }, + { + id: 4, + name: "Charlie Brown", + email: "charlie@community.com", + role: "Member", + joinedAt: "2023-04-20", + status: "active", + }, +]; + +export default function UsersPage() { + const [open, setOpen] = useState(false); + const t = useTranslations("users"); + + return ( +
+
+ {/* Header: Title + Button for Desktop only */} +
+
+

+ {t("title")} +

+

+ {t("welcome")} +

+
+ + {/* Button: Add New User for Desktop only */} + +
+ + {/* Search + Filter */} +
+
+ + +
+ +
+
+ {/* Button: Add New User for Mobile only */} +
+ +
+
+
+ + {/* --- For Mobile Phones --- */} +
+ {tempUsers.map((user) => ( + + ))} +
+ + {/* Users List / Table */} +
+ + + + + + + + + + + + {/* Example Row */} + {tempUsers.map((user) => ( + + + + + + + + ))} + +
+ User + + Role + + Status + + Joined +
+
+
+ {user.name.charAt(0)} +
+
+
+ {user.name} +
+
+ {user.email} +
+
+
+
+ + {user.role} + + + + {user.status} + + + {user.joinedAt} + + +
+
+
+ ); +} diff --git a/app/[locale]/layout.tsx b/app/[locale]/layout.tsx new file mode 100644 index 0000000..0ae30a3 --- /dev/null +++ b/app/[locale]/layout.tsx @@ -0,0 +1,45 @@ +import { routing } from "@/i18n/routing"; +import type { Metadata } from "next"; +import { NextIntlClientProvider } from "next-intl"; +import { ThemeProvider } from "next-themes"; +import { Geist, Geist_Mono } from "next/font/google"; +import "../globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "CGR App", + description: "Manager for CGR Data", +}; + +export default async function RootLayout({ + children, + params, +}: Readonly<{ + children: React.ReactNode; + params: { locale?: string }; +}>) { + const { locale } = await params; + + return ( + + + + + {children} + + + + + ); +} diff --git a/app/layout.tsx b/app/layout.tsx index 8ed844e..03bcd6e 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,35 +1,11 @@ -import type { Metadata } from "next"; -import { ThemeProvider } from "next-themes"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; +import { ReactNode } from "react"; -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - -export const metadata: Metadata = { - title: "CGR App", - description: "Manager for CGR Data", +type Props = { + children: ReactNode; }; -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - - {children} - - - - ); +// Since we have a `not-found.tsx` page on the root, a layout file +// is required, even if it's just passing children through. +export default function RootLayout({ children }: Props) { + return children; } diff --git a/components/Header.tsx b/components/Header.tsx index a348fed..48150af 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,18 +1,40 @@ +"use client"; + +import { useTranslations } from "next-intl"; import Image from "next/image"; import Link from "next/link"; import NavItems from "./NavItems"; import UserDropdown from "./UserDropdown"; const Header = () => { + const t = useTranslations(); + return ( -
-
+
+
- CGR Logo + {t("header.title")} +
+ + EN + + + DE + + + RU + +
diff --git a/components/NavItems/NavItem.tsx b/components/NavItems/NavItem.tsx index a597494..939b988 100644 --- a/components/NavItems/NavItem.tsx +++ b/components/NavItems/NavItem.tsx @@ -1,17 +1,21 @@ "use client"; +import { useTranslations } from "next-intl"; import Link from "next/link"; import { usePathname } from "next/navigation"; type NavItemProps = { item: { - label: string; + labelKey: string; href: string; }; }; -export const NavItem: React.FC = ({ item: { label, href } }) => { +export const NavItem: React.FC = ({ + item: { labelKey, href }, +}) => { const pathname = usePathname(); + const t = useTranslations(); const isActive = (path: string) => { if (path === "/") return pathname === "/"; @@ -19,12 +23,13 @@ export const NavItem: React.FC = ({ item: { label, href } }) => { }; const active = isActive(href); + const label = t(labelKey); return (
  • {label} diff --git a/i18n/navigation.ts b/i18n/navigation.ts new file mode 100644 index 0000000..e7a18ea --- /dev/null +++ b/i18n/navigation.ts @@ -0,0 +1,7 @@ +import { createNavigation } from "next-intl/navigation"; +import { routing } from "./routing"; + +// Lightweight wrappers around Next.js' navigation +// APIs that consider the routing configuration +export const { Link, redirect, usePathname, useRouter, getPathname } = + createNavigation(routing); diff --git a/i18n/request.ts b/i18n/request.ts new file mode 100644 index 0000000..4dfb90e --- /dev/null +++ b/i18n/request.ts @@ -0,0 +1,16 @@ +import { hasLocale } from "next-intl"; +import { getRequestConfig } from "next-intl/server"; +import { routing } from "./routing"; + +export default getRequestConfig(async ({ requestLocale }) => { + // Typically corresponds to the `[locale]` segment + const requested = await requestLocale; + const locale = hasLocale(routing.locales, requested) + ? requested + : routing.defaultLocale; + + return { + locale, + messages: (await import(`../messages/${locale}.json`)).default, + }; +}); diff --git a/i18n/routing.ts b/i18n/routing.ts new file mode 100644 index 0000000..a34e91f --- /dev/null +++ b/i18n/routing.ts @@ -0,0 +1,9 @@ +import { defineRouting } from "next-intl/routing"; + +export const routing = defineRouting({ + // A list of all locales that are supported + locales: ["en", "de", "ru"], + + // Used when no locale matches + defaultLocale: "en", +}); diff --git a/lib/constans.ts b/lib/constans.ts index 585b7bf..4dcbf0c 100644 --- a/lib/constans.ts +++ b/lib/constans.ts @@ -1,6 +1,6 @@ export const NAV_ITEMS = [ - { label: "Home", href: "/" }, - { label: "About", href: "/about" }, - { label: "Contact", href: "/contact" }, - { label: "Admin", href: "/admin" }, + { labelKey: "nav.home", href: "/" }, + { labelKey: "nav.about", href: "/about" }, + { labelKey: "nav.contact", href: "/contact" }, + { labelKey: "nav.admin", href: "/admin" }, ]; diff --git a/messages/de.json b/messages/de.json new file mode 100644 index 0000000..42520f6 --- /dev/null +++ b/messages/de.json @@ -0,0 +1,19 @@ +{ + "header": { + "title": "CGR Anwendung" + }, + "nav": { + "home": "Startseite", + "about": "Über", + "contact": "Kontakt", + "admin": "Admin" + }, + "dashboard": { + "title": "Community-Dashboard", + "welcome": "Willkommen im Admin-Bereich. Verwalten Sie Ihre Community-Ressourcen sicher." + }, + "users": { + "title": "Benutzer", + "welcome": "Verwalten Sie hier Ihre Community-Mitglieder, Rollen und Berechtigungen." + } +} \ No newline at end of file diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..f74d8bc --- /dev/null +++ b/messages/en.json @@ -0,0 +1,15 @@ +{ + "header": { + "title": "CGR App" + }, + "nav": { + "home": "Home", + "about": "About", + "contact": "Contact", + "admin": "Admin" + }, + "dashboard": { + "title": "Community Dashboard", + "welcome": "Welcome to the admin area. Manage your community resources safely." + } +} \ No newline at end of file diff --git a/messages/ru.json b/messages/ru.json new file mode 100644 index 0000000..af4b63d --- /dev/null +++ b/messages/ru.json @@ -0,0 +1,19 @@ +{ + "header": { + "title": "CGR Приложение" + }, + "nav": { + "home": "Главная", + "about": "О нас", + "contact": "Контакт", + "admin": "Админ" + }, + "dashboard": { + "title": "Community Dashboard", + "welcome": "Добро пожаловать в административный раздел. Безопасно управляйте ресурсами вашего сообщества." + }, + "users": { + "title": "Пользователи", + "welcome": "Управляйте членами вашего сообщества, ролями и разрешениями здесь." + } +} \ No newline at end of file diff --git a/next-intl.config.js b/next-intl.config.js new file mode 100644 index 0000000..44ed5f1 --- /dev/null +++ b/next-intl.config.js @@ -0,0 +1,7 @@ +/** @type {import('next-intl').NextIntlConfig} */ +module.exports = { + locales: ['en', 'de', 'ru'], + defaultLocale: 'en', + // Directory where your message JSON files live + messagesDirectory: './messages' +}; diff --git a/next.config.ts b/next.config.ts index ad52782..9addf99 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,8 +1,11 @@ import type { NextConfig } from "next"; +import createNextIntlPlugin from "next-intl/plugin"; + +const withNextIntl = createNextIntlPlugin("./i18n/request.ts"); const nextConfig: NextConfig = { output: "standalone", /* config options here */ }; -export default nextConfig; +export default withNextIntl(nextConfig); diff --git a/package-lock.json b/package-lock.json index bf128dd..34f6441 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "date-fns": "^4.1.0", "lucide-react": "^0.563.0", "next": "16.1.4", + "next-intl": "^4.8.2", "next-themes": "^0.4.6", "react": "19.2.3", "react-day-picker": "^9.13.0", @@ -519,6 +520,67 @@ "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", "license": "MIT" }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-3.1.1.tgz", + "integrity": "sha512-jhZbTwda+2tcNrs4kKvxrPLPjx8QsBCLCUgrrJ/S+G9YrGHWLhAyFMMBHJBnBoOwuLHd7L14FgYudviKaxkO2Q==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "3.1.0", + "@formatjs/intl-localematcher": "0.8.1", + "decimal.js": "^10.6.0", + "tslib": "^2.8.1" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.1.tgz", + "integrity": "sha512-xwEuwQFdtSq1UKtQnyTZWC+eHdv7Uygoa+H2k/9uzBVQjDyp9r20LNDNKedWXll7FssT3GRHvqsdJGYSUWqYFA==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "3.1.0", + "tslib": "^2.8.1" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.0.tgz", + "integrity": "sha512-b5mvSWCI+XVKiz5WhnBCY3RJ4ZwfjAidU0yVlKa3d3MSgKmH1hC3tBGEAtYyN5mqL7N0G5x0BOUYyO8CEupWgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.1.tgz", + "integrity": "sha512-sSDmSvmmoVQ92XqWb499KrIhv/vLisJU8ITFrx7T7NZHUmMY7EL9xgRowAosaljhqnj/5iufG24QrdzB6X3ItA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "3.1.1", + "@formatjs/icu-skeleton-parser": "2.1.1", + "tslib": "^2.8.1" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.1.tgz", + "integrity": "sha512-PSFABlcNefjI6yyk8f7nyX1DC7NHmq6WaCHZLySEXBrXuLOB2f935YsnzuPjlz+ibhb9yWTdPeVX1OVcj24w2Q==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "3.1.1", + "tslib": "^2.8.1" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz", + "integrity": "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==", + "license": "MIT", + "dependencies": { + "tslib": "2" + } + }, "node_modules/@hookform/resolvers": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.2.2.tgz", @@ -1304,6 +1366,313 @@ "node": ">=12.4.0" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@radix-ui/number": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", @@ -2215,12 +2584,184 @@ "dev": true, "license": "MIT" }, + "node_modules/@schummar/icu-type-parser": { + "version": "1.21.5", + "resolved": "https://registry.npmjs.org/@schummar/icu-type-parser/-/icu-type-parser-1.21.5.tgz", + "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==", + "license": "MIT" + }, "node_modules/@standard-schema/utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", "license": "MIT" }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.11.tgz", + "integrity": "sha512-QoIupRWVH8AF1TgxYyeA5nS18dtqMuxNwchjBIwJo3RdwLEFiJq6onOx9JAxHtuPwUkIVuU2Xbp+jCJ7Vzmgtg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.11.tgz", + "integrity": "sha512-S52Gu1QtPSfBYDiejlcfp9GlN+NjTZBRRNsz8PNwBgSE626/FUf2PcllVUix7jqkoMC+t0rS8t+2/aSWlMuQtA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.11.tgz", + "integrity": "sha512-lXJs8oXo6Z4yCpimpQ8vPeCjkgoHu5NoMvmJZ8qxDyU99KVdg6KwU9H79vzrmB+HfH+dCZ7JGMqMF//f8Cfvdg==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.11.tgz", + "integrity": "sha512-chRsz1K52/vj8Mfq/QOugVphlKPWlMh10V99qfH41hbGvwAU6xSPd681upO4bKiOr9+mRIZZW+EfJqY42ZzRyA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.11.tgz", + "integrity": "sha512-PYftgsTaGnfDK4m6/dty9ryK1FbLk+LosDJ/RJR2nkXGc8rd+WenXIlvHjWULiBVnS1RsjHHOXmTS4nDhe0v0w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.11.tgz", + "integrity": "sha512-DKtnJKIHiZdARyTKiX7zdRjiDS1KihkQWatQiCHMv+zc2sfwb4Glrodx2VLOX4rsa92NLR0Sw8WLcPEMFY1szQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.11.tgz", + "integrity": "sha512-mUjjntHj4+8WBaiDe5UwRNHuEzLjIWBTSGTw0JT9+C9/Yyuh4KQqlcEQ3ro6GkHmBGXBFpGIj/o5VMyRWfVfWw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.11.tgz", + "integrity": "sha512-ZkNNG5zL49YpaFzfl6fskNOSxtcZ5uOYmWBkY4wVAvgbSAQzLRVBp+xArGWh2oXlY/WgL99zQSGTv7RI5E6nzA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.11.tgz", + "integrity": "sha512-6XnzORkZCQzvTQ6cPrU7iaT9+i145oLwnin8JrfsLG41wl26+5cNQ2XV3zcbrnFEV6esjOceom9YO1w9mGJByw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.11.tgz", + "integrity": "sha512-IQ2n6af7XKLL6P1gIeZACskSxK8jWtoKpJWLZmdXTDj1MGzktUy4i+FvpdtxFmJWNavRWH1VmTr6kAubRDHeKw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -2230,6 +2771,15 @@ "tslib": "^2.8.0" } }, + "node_modules/@swc/types": { + "version": "0.1.25", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.25.tgz", + "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@tailwindcss/node": { "version": "4.1.18", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.18.tgz", @@ -3748,6 +4298,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3795,7 +4351,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -4942,6 +5497,21 @@ "hermes-estree": "0.25.1" } }, + "node_modules/icu-minify": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.8.2.tgz", + "integrity": "sha512-LHBQV+skKkjZSPd590pZ7ZAHftUgda3eFjeuNwA8/15L8T8loCNBktKQyTlkodAU86KovFXeg/9WntlAo5wA5A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/icu-messageformat-parser": "^3.4.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4994,6 +5564,18 @@ "node": ">= 0.4" } }, + "node_modules/intl-messageformat": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.1.2.tgz", + "integrity": "sha512-ucSrQmZGAxfiBHfBRXW/k7UC8MaGFlEj4Ry1tKiDcmgwQm1y3EDl40u+4VNHYomxJQMJi9NEI3riDRlth96jKg==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "3.1.1", + "@formatjs/fast-memoize": "3.1.0", + "@formatjs/icu-messageformat-parser": "3.5.1", + "tslib": "^2.8.1" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -5156,7 +5738,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5202,7 +5783,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -6009,6 +6589,15 @@ "dev": true, "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next": { "version": "16.1.4", "resolved": "https://registry.npmjs.org/next/-/next-16.1.4.tgz", @@ -6062,6 +6651,93 @@ } } }, + "node_modules/next-intl": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.8.2.tgz", + "integrity": "sha512-GuuwyvyEI49/oehQbBXEoY8KSIYCzmfMLhmIwhMXTb+yeBmly1PnJcpgph3KczQ+HTJMXwXCmkizgtT8jBMf3A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/intl-localematcher": "^0.5.4", + "@parcel/watcher": "^2.4.1", + "@swc/core": "^1.15.2", + "icu-minify": "^4.8.2", + "negotiator": "^1.0.0", + "next-intl-swc-plugin-extractor": "^4.8.2", + "po-parser": "^2.1.1", + "use-intl": "^4.8.2" + }, + "peerDependencies": { + "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/next-intl-swc-plugin-extractor": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.8.2.tgz", + "integrity": "sha512-sHDs36L1VZmFHj3tPHsD+KZJtnsRudHlNvT0ieIe3iFVn5OpGLTxW3d/Zc/2LXSj5GpGuR6wQeikbhFjU9tMQQ==", + "license": "MIT" + }, + "node_modules/next-intl/node_modules/@swc/core": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.11.tgz", + "integrity": "sha512-iLmLTodbYxU39HhMPaMUooPwO/zqJWvsqkrXv1ZI38rMb048p6N7qtAtTp37sw9NzSrvH6oli8EdDygo09IZ/w==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.25" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.11", + "@swc/core-darwin-x64": "1.15.11", + "@swc/core-linux-arm-gnueabihf": "1.15.11", + "@swc/core-linux-arm64-gnu": "1.15.11", + "@swc/core-linux-arm64-musl": "1.15.11", + "@swc/core-linux-x64-gnu": "1.15.11", + "@swc/core-linux-x64-musl": "1.15.11", + "@swc/core-win32-arm64-msvc": "1.15.11", + "@swc/core-win32-ia32-msvc": "1.15.11", + "@swc/core-win32-x64-msvc": "1.15.11" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/next-intl/node_modules/@swc/helpers": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.18.tgz", + "integrity": "sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==", + "license": "Apache-2.0", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/next-themes": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", @@ -6100,6 +6776,12 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", @@ -6357,6 +7039,12 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/po-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz", + "integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==", + "license": "MIT" + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -7532,7 +8220,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7689,6 +8377,27 @@ } } }, + "node_modules/use-intl": { + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.8.2.tgz", + "integrity": "sha512-3VNXZgDnPFqhIYosQ9W1Hc6K5q+ZelMfawNbexdwL/dY7BTHbceLUBX5Eeex9lgogxTp0pf1SjHuhYNAjr9H3g==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "^3.1.0", + "@schummar/icu-type-parser": "1.21.5", + "icu-minify": "^4.8.2", + "intl-messageformat": "^11.1.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + } + }, "node_modules/use-sidecar": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", diff --git a/package.json b/package.json index 6b39b4e..6c5f707 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "date-fns": "^4.1.0", "lucide-react": "^0.563.0", "next": "16.1.4", + "next-intl": "^4.8.2", "next-themes": "^0.4.6", "react": "19.2.3", "react-day-picker": "^9.13.0", diff --git a/proxy.ts b/proxy.ts new file mode 100644 index 0000000..ed0e55f --- /dev/null +++ b/proxy.ts @@ -0,0 +1,11 @@ +import createMiddleware from "next-intl/middleware"; +import { routing } from "./i18n/routing"; + +export default createMiddleware(routing); + +export const config = { + // Match all pathnames except for + // - … if they start with `/api`, `/trpc`, `/_next` or `/_vercel` + // - … the ones containing a dot (e.g. `favicon.ico`) + matcher: "/((?!api|trpc|_next|_vercel|.*\\..*).*)", +};