i18n con next-intl: raíz multilenguaje (es por defecto, /en) + textos externalizados

- next-intl 4 (compatible Next 16): routing (es default en RAÍZ sin prefijo, en con
  /en, localePrefix 'as-needed'), middleware, request config, navigation helpers.
- Estructura app/[locale]/ (layout con <html lang>, NextIntlClientProvider, metadata
  SEO por idioma vía generateMetadata; page home con getTranslations).
- Catálogos messages/es.json y en.json: TODOS los textos de la UI (nada hardcodeado
  en los .tsx, se usan con t()).

Verificado: / -> español (lang=es, título ES), /en -> inglés (lang=en, título EN),
datos SSR desde MySQL. Añadir idioma = locale en routing + messages/<loc>.json.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 22:31:27 +00:00
parent c36b543184
commit 032bd0020b
12 changed files with 816 additions and 52 deletions
+52
View File
@@ -0,0 +1,52 @@
import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
import { NextIntlClientProvider, hasLocale } from 'next-intl'
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { routing } from '@/i18n/routing'
import '../globals.css'
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }))
}
// SEO por idioma (SSR) vía Metadata API.
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: string }>
}): Promise<Metadata> {
const { locale } = await params
const t = await getTranslations({ locale, namespace: 'Metadata' })
return {
title: t('title'),
description: t('description'),
openGraph: {
siteName: 'Nova WoW',
title: t('title'),
description: t('description'),
type: 'website',
locale: locale === 'es' ? 'es_ES' : 'en_US',
url: 'https://www.nightspire.gg/',
},
}
}
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ locale: string }>
}) {
const { locale } = await params
if (!hasLocale(routing.locales, locale)) notFound()
setRequestLocale(locale)
return (
<html lang={locale}>
<body>
<NextIntlClientProvider>{children}</NextIntlClientProvider>
</body>
</html>
)
}
@@ -1,7 +1,7 @@
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { getNoticias, getServerStatus, type Noticia, type ServerStatus } from '@/lib/home'
// SSR por petición: los datos se leen DIRECTAMENTE de MySQL desde el servidor Next
// (sin Django). force-dynamic para renderizar por petición.
// SSR por petición: los datos se leen DIRECTAMENTE de MySQL desde el servidor Next.
export const dynamic = 'force-dynamic'
async function getData(): Promise<{ noticias: Noticia[]; status: ServerStatus | null }> {
@@ -12,47 +12,54 @@ async function getData(): Promise<{ noticias: Noticia[]; status: ServerStatus |
}
}
export default async function HomePage() {
export default async function HomePage({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params
setRequestLocale(locale)
const t = await getTranslations('Home')
const { noticias, status } = await getData()
return (
<main className="mx-auto max-w-3xl px-4 py-8">
<h1 className="text-3xl font-bold text-amber-500">Nova WoW</h1>
<h1 className="text-3xl font-bold text-amber-500">{t('brand')}</h1>
<section className="my-6 rounded-lg border border-amber-900/60 bg-[#241812] p-4">
<h2 className="mb-3 text-lg font-semibold">Estado del servidor</h2>
<h2 className="mb-3 text-lg font-semibold">{t('serverStatus')}</h2>
{status ? (
<ul className="space-y-1 text-sm">
<li>
Servidor: <span className="text-amber-400">{status.server_name ?? '—'}</span> ({status.expansion})
{t('server')}: <span className="text-amber-400">{status.server_name ?? '—'}</span> ({status.expansion})
</li>
<li>Personajes en línea: {status.online_characters}</li>
<li>
Login:{' '}
{t('onlineCharacters')}: {status.online_characters}
</li>
<li>
{t('login')}:{' '}
<span className={status.status === 'Online' ? 'text-green-400' : 'text-red-400'}>{status.status}</span>
</li>
<li>Dirección: {status.address ?? '—'}</li>
<li>
{t('address')}: {status.address ?? '—'}
</li>
</ul>
) : (
<p>No disponible.</p>
<p>{t('notAvailable')}</p>
)}
</section>
<section>
<h2 className="mb-3 text-lg font-semibold">Noticias</h2>
<h2 className="mb-3 text-lg font-semibold">{t('news')}</h2>
{noticias.length === 0 ? (
<p className="text-amber-200/70">No hay noticias disponibles en este momento.</p>
<p className="text-amber-200/70">{t('noNews')}</p>
) : (
noticias.map((n) => (
<article key={n.id} className="mb-4 border-b border-amber-900/60 pb-4">
<h3 className="text-xl font-semibold">{n.titulo}</h3>
{n.fecha && <small className="text-amber-200/60">{new Date(n.fecha).toLocaleString('es-ES')}</small>}
{n.fecha && <small className="text-amber-200/60">{new Date(n.fecha).toLocaleString(locale)}</small>}
<div className="prose prose-invert mt-2 max-w-none" dangerouslySetInnerHTML={{ __html: n.contenido }} />
{n.enlace && (
<p className="mt-2">
Enlace:{' '}
{t('link')}:{' '}
<a className="text-sky-400 underline" href={n.enlace} target="_blank" rel="noopener noreferrer">
aquí
{t('here')}
</a>
</p>
)}
-31
View File
@@ -1,31 +0,0 @@
import type { Metadata } from 'next'
import './globals.css'
const SERVER = 'Nova WoW'
// SEO renderizado en servidor (SSR) — equivale a las meta de la antigua head.html.
export const metadata: Metadata = {
title: `${SERVER} Server de WoW WotLK 3.4.3 Latino y Español 💎`,
description: `Descarga y juega gratis a WotLK Classic en ${SERVER} - Server de WoW WotLK 3.4.3 Latino y Español - El mejor server de WoW 🔥`,
keywords: [
'server wow', 'server wotlk', 'server 3.4.3', 'wotlk classic',
'servidor de wow', 'servidor wotlk', 'wow 3.4.3 latino', 'wow 3.4.3 español',
'server wow en español', 'el mejor server de wow', SERVER,
],
openGraph: {
siteName: SERVER,
title: `${SERVER} Server de WoW WotLK 3.4.3 Latino y Español 💎`,
description: `Juega gratis WotLK Classic en ${SERVER} - Server de WoW 3.4.3 Latino y Español`,
type: 'website',
locale: 'es_ES',
url: 'https://www.nightspire.gg/',
},
}
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
return (
<html lang="es">
<body>{children}</body>
</html>
)
}
+5
View File
@@ -0,0 +1,5 @@
import { createNavigation } from 'next-intl/navigation'
import { routing } from './routing'
// Wrappers de navegación conscientes del idioma (Link, useRouter, redirect...).
export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing)
+12
View File
@@ -0,0 +1,12 @@
import { getRequestConfig } from 'next-intl/server'
import { hasLocale } from 'next-intl'
import { routing } from './routing'
export default getRequestConfig(async ({ requestLocale }) => {
const requested = await requestLocale
const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale
return {
locale,
messages: (await import(`../messages/${locale}.json`)).default,
}
})
+9
View File
@@ -0,0 +1,9 @@
import { defineRouting } from 'next-intl/routing'
// Idiomas soportados. El por defecto (es) se sirve en RAÍZ (sin prefijo);
// los demás con prefijo (/en). Añadir un idioma = añadirlo aquí + messages/<loc>.json.
export const routing = defineRouting({
locales: ['es', 'en'],
defaultLocale: 'es',
localePrefix: 'as-needed',
})
+19
View File
@@ -0,0 +1,19 @@
{
"Metadata": {
"title": "Nova WoW WoW WotLK 3.4.3 Server - Latino & Español 💎",
"description": "Download and play WotLK Classic for free on Nova WoW - WoW WotLK 3.4.3 server - The best WoW server 🔥"
},
"Home": {
"brand": "Nova WoW",
"serverStatus": "Server status",
"server": "Server",
"onlineCharacters": "Online characters",
"login": "Login",
"address": "Address",
"notAvailable": "Not available",
"news": "News",
"noNews": "There are no news available at the moment.",
"link": "Link",
"here": "here"
}
}
+19
View File
@@ -0,0 +1,19 @@
{
"Metadata": {
"title": "Nova WoW Server de WoW WotLK 3.4.3 Latino y Español 💎",
"description": "Descarga y juega gratis a WotLK Classic en Nova WoW - Server de WoW WotLK 3.4.3 Latino y Español - El mejor server de WoW 🔥"
},
"Home": {
"brand": "Nova WoW",
"serverStatus": "Estado del servidor",
"server": "Servidor",
"onlineCharacters": "Personajes en línea",
"login": "Login",
"address": "Dirección",
"notAvailable": "No disponible",
"news": "Noticias",
"noNews": "No hay noticias disponibles en este momento.",
"link": "Enlace",
"here": "aquí"
}
}
+9
View File
@@ -0,0 +1,9 @@
import createMiddleware from 'next-intl/middleware'
import { routing } from './i18n/routing'
export default createMiddleware(routing)
export const config = {
// Aplica a todo salvo /api, estáticos de Next e ipas con extensión.
matcher: ['/((?!api|_next|_vercel|.*\\..*).*)'],
}
+6 -3
View File
@@ -1,7 +1,10 @@
import type { NextConfig } from "next";
import type { NextConfig } from 'next'
import createNextIntlPlugin from 'next-intl/plugin'
const withNextIntl = createNextIntlPlugin('./i18n/request.ts')
const nextConfig: NextConfig = {
/* config options here */
};
}
export default nextConfig;
export default withNextIntl(nextConfig)
+662 -3
View File
@@ -10,6 +10,7 @@
"dependencies": {
"mysql2": "^3.22.6",
"next": "16.2.10",
"next-intl": "^4.13.2",
"react": "19.2.4",
"react-dom": "19.2.4"
},
@@ -424,6 +425,32 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@formatjs/fast-memoize": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.7.tgz",
"integrity": "sha512-zXfhLpvA6T7+efdt9JLbBwZ00tT7NsBMDVnDu8rpHeNNv8KfRZAMo2gkG0k9lK/Nzc//3kJ9pImsfuJxk3KhUA=="
},
"node_modules/@formatjs/icu-messageformat-parser": {
"version": "3.5.14",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.14.tgz",
"integrity": "sha512-jDvgtoLqe3U6yzoBlToMTkWBe38qSi7LN7kFlnXzd5ig8nn+4tSlED0xtEtdYakZVZGJJY2rW1D5xS3BFZh6kA==",
"dependencies": {
"@formatjs/icu-skeleton-parser": "2.1.11"
}
},
"node_modules/@formatjs/icu-skeleton-parser": {
"version": "2.1.11",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.11.tgz",
"integrity": "sha512-j8cUmOJzVgkHuS0QiQ6ga76UIoLOFSAMWhs7aZJztH3aAdCOAE6vpC8KVvFB4cU10ON0y2/5oOVmPJ43s2lTwA=="
},
"node_modules/@formatjs/intl-localematcher": {
"version": "0.8.12",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.12.tgz",
"integrity": "sha512-5H3r5ZJ2jZqHEv9K343lvHmeMDKMxssawAVD2H4J9xtu0ZXb6MlNxwLqdwBxJSHFU0C24KSZnffgmAi+59mK4A==",
"dependencies": {
"@formatjs/fast-memoize": "3.1.7"
}
},
"node_modules/@humanfs/core": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
@@ -1167,12 +1194,494 @@
"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,
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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"
],
"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.5",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
"integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
"dev": true
},
"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=="
},
"node_modules/@swc/core-darwin-arm64": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz",
"integrity": "sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-darwin-x64": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz",
"integrity": "sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm-gnueabihf": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz",
"integrity": "sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-gnu": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz",
"integrity": "sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-arm64-musl": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz",
"integrity": "sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-ppc64-gnu": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz",
"integrity": "sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-s390x-gnu": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz",
"integrity": "sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-gnu": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz",
"integrity": "sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-linux-x64-musl": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz",
"integrity": "sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-arm64-msvc": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz",
"integrity": "sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-ia32-msvc": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz",
"integrity": "sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@swc/core-win32-x64-msvc": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz",
"integrity": "sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==",
"cpu": [
"x64"
],
"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=="
},
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -1181,6 +1690,14 @@
"tslib": "^2.8.0"
}
},
"node_modules/@swc/types": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.27.tgz",
"integrity": "sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg==",
"dependencies": {
"@swc/counter": "^0.1.3"
}
},
"node_modules/@tailwindcss/node": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.2.tgz",
@@ -2718,7 +3235,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"devOptional": true,
"engines": {
"node": ">=8"
}
@@ -3808,6 +4324,20 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/icu-minify": {
"version": "4.13.2",
"resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.13.2.tgz",
"integrity": "sha512-XhYQTEnBXBCyF6ERiwItFweoOXDUciujaGjIWCA7RhOCEPDfhVSTtuwfRq6HdVk7tKnYJh+yaurP96zGnaKsPg==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/amannn"
}
],
"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",
@@ -3856,6 +4386,15 @@
"node": ">= 0.4"
}
},
"node_modules/intl-messageformat": {
"version": "11.2.11",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.11.tgz",
"integrity": "sha512-aDG5bvFRbQvRoT2Bh9FV6yV8t7o0MjEGknZ6pnin5Wt52PJwaBOHDfvz+oPEe78Pl3InQYKugBgCdXijLj6viQ==",
"dependencies": {
"@formatjs/fast-memoize": "3.1.7",
"@formatjs/icu-messageformat-parser": "3.5.14"
}
},
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -4023,7 +4562,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -4066,7 +4604,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"dependencies": {
"is-extglob": "^2.1.1"
},
@@ -4874,6 +5411,14 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"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==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/next": {
"version": "16.2.10",
"resolved": "https://registry.npmjs.org/next/-/next-16.2.10.tgz",
@@ -4926,6 +5471,95 @@
}
}
},
"node_modules/next-intl": {
"version": "4.13.2",
"resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.13.2.tgz",
"integrity": "sha512-iCYycEP7/PE+1ue4MWBuz1qns6ESA+SGzuXxNMNN1qiYUh2fLhJPiZvHW1zZC7zMTn44aJUglOVZxUb1+hUz6g==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/amannn"
}
],
"dependencies": {
"@formatjs/intl-localematcher": "^0.8.1",
"@parcel/watcher": "^2.4.1",
"@swc/core": "^1.15.2",
"icu-minify": "^4.13.2",
"negotiator": "^1.0.0",
"next-intl-swc-plugin-extractor": "^4.13.2",
"po-parser": "^2.1.1",
"use-intl": "^4.13.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"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/next-intl-swc-plugin-extractor": {
"version": "4.13.2",
"resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.13.2.tgz",
"integrity": "sha512-O30N/Y4ifzRe5Sz80jD1Qkg4VY6Zfef4SbHNNE166QkHswBf3/Kygpdd1X52sUUwTCk6uvdisO8ybfAN/VYJHQ=="
},
"node_modules/next-intl/node_modules/@swc/core": {
"version": "1.15.43",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.43.tgz",
"integrity": "sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==",
"hasInstallScript": true,
"dependencies": {
"@swc/counter": "^0.1.3",
"@swc/types": "^0.1.27"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/swc"
},
"optionalDependencies": {
"@swc/core-darwin-arm64": "1.15.43",
"@swc/core-darwin-x64": "1.15.43",
"@swc/core-linux-arm-gnueabihf": "1.15.43",
"@swc/core-linux-arm64-gnu": "1.15.43",
"@swc/core-linux-arm64-musl": "1.15.43",
"@swc/core-linux-ppc64-gnu": "1.15.43",
"@swc/core-linux-s390x-gnu": "1.15.43",
"@swc/core-linux-x64-gnu": "1.15.43",
"@swc/core-linux-x64-musl": "1.15.43",
"@swc/core-win32-arm64-msvc": "1.15.43",
"@swc/core-win32-ia32-msvc": "1.15.43",
"@swc/core-win32-x64-msvc": "1.15.43"
},
"peerDependencies": {
"@swc/helpers": ">=0.5.17"
},
"peerDependenciesMeta": {
"@swc/helpers": {
"optional": true
}
}
},
"node_modules/next-intl/node_modules/@swc/helpers": {
"version": "0.5.23",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
"integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
"optional": true,
"peer": true,
"dependencies": {
"tslib": "^2.8.0"
}
},
"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=="
},
"node_modules/node-exports-info": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz",
@@ -5185,6 +5819,11 @@
"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=="
},
"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",
@@ -6231,6 +6870,26 @@
"punycode": "^2.1.0"
}
},
"node_modules/use-intl": {
"version": "4.13.2",
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.13.2.tgz",
"integrity": "sha512-p6/gCromeBoec+wEuOIkPaytH77RBjW94KWv8MRsNrbI4UOx8QgwNhgl9lbPOKM/b0dpanLhCYztLEH5yQUjtg==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/amannn"
}
],
"dependencies": {
"@formatjs/fast-memoize": "^3.1.0",
"@schummar/icu-type-parser": "1.21.5",
"icu-minify": "^4.13.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/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+1
View File
@@ -11,6 +11,7 @@
"dependencies": {
"mysql2": "^3.22.6",
"next": "16.2.10",
"next-intl": "^4.13.2",
"react": "19.2.4",
"react-dom": "19.2.4"
},