Noticias multiidioma (ES/EN) con fallback
home_noticia gana columnas titulo_en/contenido_en (sql/add_news_en.sql). getNoticias(locale) usa la versión EN si existe, si no cae al español (título y contenido independientes); la fecha también se formatea por idioma. El panel de admin permite escribir la traducción al crear y EDITAR noticias existentes (nuevo PUT /api/admin/news/[id], updateNews). Claves Admin nuevas (título/ contenido EN, editar/guardar). Probado: /en/ muestra EN, /es/ ES; PUT guardado (403 sin sesión). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,8 +7,8 @@ import { getRealmName } from '@/lib/realm'
|
||||
// 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 }> {
|
||||
const [news, status] = await Promise.allSettled([getNoticias(), getServerStatus()])
|
||||
async function getData(locale: string): Promise<{ noticias: Noticia[]; status: ServerStatus | null }> {
|
||||
const [news, status] = await Promise.allSettled([getNoticias(locale), getServerStatus()])
|
||||
return {
|
||||
noticias: news.status === 'fulfilled' ? news.value : [],
|
||||
status: status.status === 'fulfilled' ? status.value : null,
|
||||
@@ -24,11 +24,11 @@ function brandify(html: string, realm: string): string {
|
||||
return html.replace(/<[^>]*>|[^<]+/g, (seg) => (seg.startsWith('<') ? seg : seg.replace(re, repl)))
|
||||
}
|
||||
|
||||
function formatFecha(iso: string | Date | null): string {
|
||||
function formatFecha(iso: string | Date | null, locale: string): string {
|
||||
if (!iso) return ''
|
||||
const d = new Date(iso)
|
||||
if (isNaN(d.getTime())) return String(iso)
|
||||
return d.toLocaleDateString('es-ES', {
|
||||
return d.toLocaleDateString(locale === 'en' ? 'en-US' : 'es-ES', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
@@ -39,7 +39,7 @@ export default async function HomePage({ params }: { params: Promise<{ locale: s
|
||||
const { locale } = await params
|
||||
setRequestLocale(locale)
|
||||
const t = await getTranslations('Misc')
|
||||
const { noticias, status } = await getData()
|
||||
const { noticias, status } = await getData(locale)
|
||||
const realmName = await getRealmName()
|
||||
|
||||
const worldStatus = status ? status.world_status : 'Offline'
|
||||
@@ -125,7 +125,7 @@ export default async function HomePage({ params }: { params: Promise<{ locale: s
|
||||
{noticias.map((n) => (
|
||||
<div key={n.id} className="noticia-item">
|
||||
<h3>{brandify(n.titulo, realmName)}</h3>
|
||||
<span className="date">{formatFecha(n.fecha)}</span>
|
||||
<span className="date">{formatFecha(n.fecha, locale)}</span>
|
||||
<p
|
||||
className="noticia-contenido"
|
||||
dangerouslySetInnerHTML={{ __html: brandify(n.contenido, realmName) }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getSession } from '@/lib/session'
|
||||
import { isAdmin } from '@/lib/admin'
|
||||
import { deleteNews } from '@/lib/admin-news'
|
||||
import { deleteNews, updateNews } from '@/lib/admin-news'
|
||||
|
||||
export async function DELETE(_request: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
@@ -9,3 +9,19 @@ export async function DELETE(_request: Request, { params }: { params: Promise<{
|
||||
await deleteNews(Number(id))
|
||||
return Response.json({ success: true })
|
||||
}
|
||||
|
||||
export async function PUT(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||
const session = await getSession()
|
||||
if (!(await isAdmin(session))) return Response.json({ success: false, error: 'forbidden' }, { status: 403 })
|
||||
const { id } = await params
|
||||
let b: Record<string, string> = {}
|
||||
try { b = await request.json() } catch { return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 }) }
|
||||
const titulo = String(b.titulo ?? '').trim()
|
||||
const contenido = String(b.contenido ?? '').trim()
|
||||
const enlace = String(b.enlace ?? '').trim() || null
|
||||
const tituloEn = String(b.tituloEn ?? '').trim() || null
|
||||
const contenidoEn = String(b.contenidoEn ?? '').trim() || null
|
||||
if (!titulo || !contenido) return Response.json({ success: false, error: 'emptyError' })
|
||||
await updateNews(Number(id), titulo, contenido, enlace, tituloEn, contenidoEn)
|
||||
return Response.json({ success: true })
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ export async function POST(request: Request) {
|
||||
const titulo = String(b.titulo ?? '').trim()
|
||||
const contenido = String(b.contenido ?? '').trim()
|
||||
const enlace = String(b.enlace ?? '').trim() || null
|
||||
const tituloEn = String(b.tituloEn ?? '').trim() || null
|
||||
const contenidoEn = String(b.contenidoEn ?? '').trim() || null
|
||||
if (!titulo || !contenido) return Response.json({ success: false, error: 'emptyError' })
|
||||
const id = await createNews(titulo, contenido, enlace)
|
||||
const id = await createNews(titulo, contenido, enlace, tituloEn, contenidoEn)
|
||||
return Response.json({ success: true, id })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user